【问题标题】:EF6 Code First - Configure One-to-One relationship with unmatched foreign keysEF6 Code First - 使用不匹配的外键配置一对一关系
【发布时间】:2014-09-03 15:51:19
【问题描述】:

我使用 Code First 来定义现有数据库的架构。我遇到的问题是它们在表中的键名不太一致。这适用于一对多关系,因为我可以使用 HasForeignKey() 方法,但似乎没有对应的一对一关系。我的表定义是:

namespace Data.Mappings {

    internal class DocumentTypeConfiguration : EntityTypeConfiguration<Document> {

        public DocumentTypeConfiguration() {
            ToTable("ProsDocs");

            HasKey(m => m.Id);

            Property(m => m.Id)
                .HasColumnName("ProsDocId")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            // ---- This is the foreign key ----
            Property(m => m.TypeId)
                .HasColumnName("ProsDocTypeId")
                .HasMaxLength(3);

            HasRequired(d => d.DocType)
                .WithRequiredDependent(dt => dt.Document);
                // I need to specify here that the foreign key is named "DocTypeId" and not "DocType_Id"
        }
    }

    internal class DocTypeTypeConfiguration : EntityTypeConfiguration<DocType> {

        public DocTypeTypeConfiguration() {
            ToTable("DocType");

            HasKey(m => m.Id);

            // ---- This is the "child" end of the foreign key ----
            Property(m => m.Id)
                .HasColumnName("DocTypeId")
                .HasMaxLength(4);

            Property(m => m.FullName)
                .HasColumnName("DocTypeDesc")
                .HasMaxLength(255);

            Property(m => m.Priority)
                .HasColumnName("DocPriority");

            // Or would it be easier to define it here?
//            HasRequired(m => m.Document)
//                .WithRequiredDependent(d => d.DocType);
        }
    }
}

为了明确模型,每个Document都有一个DocType,外键关系为Document.ProsDocTypeId --&gt; DocType.Id

有没有办法为一对一关系的键定义列名?

编辑:我猜我的架构不清楚。

dbo.DocType
-----------
DocTypeId char(4) (PK)
DocTypeDesc varchar(255)

dbo.ProsDocs
------------
ProsDocId int (PK)
ProsDocTypeId char(4)

基本上,我需要生成的查询如下所示:

SELECT 
    [Extent1].[ProsDocId] AS [ProsDocId], 
    [Extent2].[DocTypeId] AS [DocTypeId]
    FROM  [dbo].[ProsDocs] AS [Extent1]
    LEFT OUTER JOIN [dbo].[DocType] AS [Extent2] ON [Extent1].[ProsDocTypeId] = [Extent2].[DocTypeId]
    WHERE [Extent1].[ProsId] = @EntityKeyValue1

但是相反,因为 EF 假设我想使用主键 (dbo.ProsDocs.ProsDocId) 而不是外键 (dbo.ProsDocs.DocTypeId),所以它生成的查询是这样的:

SELECT 
    [Extent1].[ProsDocId] AS [ProsDocId], 
    [Extent2].[DocTypeId] AS [DocTypeId]
    FROM  [dbo].[ProsDocs] AS [Extent1]
    LEFT OUTER JOIN [dbo].[DocType] AS [Extent2] ON [Extent1].[ProsDocId] = [Extent2].[ProsDocTypeId]
    WHERE [Extent1].[ProsId] = @EntityKeyValue1

区别就在这里:

理想查询:

LEFT OUTER JOIN [dbo].[DocType] AS [Extent2] ON [Extent1].[ProsDocTypeId] = [Extent2].[DocTypeId]

当前查询:

LEFT OUTER JOIN [dbo].[DocType] AS [Extent2] ON [Extent1].[ProsDocId] = [Extent2].[ProsDocTypeId]

我需要在dbo.ProsDocs.ProsDocTypeIddbo.DocType.DocTypeId 之间创建一个一对一的关系。 EF 遇到的问题是它只想使用主键而不是外键来创建关系。如何指定外键的列名,以便每个Document 都只有一个DocType

【问题讨论】:

  • 哪个是主体(必须先存在的实体)?

标签: entity-framework ef-code-first entity-framework-6


【解决方案1】:

如果Document 是主体,DocType 是从属,那么您需要

  • Document上进行此配置

    HasRequired(d => d.DocType).WithRequiredPrincipal(dt => dt.Document);
    
  • 或者DocType上的这个配置

    HasRequired(dt => dt.Document).WithRequiredDependent(d => d.DocType);
    

并从Document 中删除TypeId / ProsDocTypeId 属性,因为主体不能具有依赖的外键ID,除非它不是约束,只是普通列。

更新

实体:

public class Document
{
    public string Id { get; set; }
    // This entity is a principal. It can't have foreign key id to dependent.
    // public string TypeId { get; set; }
    public DocType DocType { get; set; }
}

林克:

db.Documents.Include(d => d.DocType)

查询:

 SELECT
    1 AS [C1],
    [Extent1].[ProsDocId] AS [ProsDocId],
    [Extent2].[DocTypeId] AS [DocTypeId],
    FROM  [dbo].[ProsDocs] AS [Extent1]
    LEFT OUTER JOIN [dbo].[DocType] AS [Extent2] ON [Extent1].[ProsDocId] = [Extent2].[DocTypeId]

更新 2

要实现理想的查询,您需要的关系是一对多的。一个DocType 可以有多个Document

public class Document
{
    public string Id { get; set; }
    public string TypeId { get; set; }
    public DocType DocType { get; set; }
}
public class DocType
{
    public string Id { get; set; }
    public string FullName { get; set; }
    public string Priority { get; set; }
    public ICollection<Document> Documents { get; set; }
}

Document上的配置。

改变这个:

HasRequired(d => d.DocType).WithRequiredDependent(dt => dt.Document);

进入:

HasRequired(d => d.DocType).WithMany(dt => dt.Documents).HasForeignKey(d => d.TypeId);

林克:

db.Documents.Include(d => d.DocType)

查询:

SELECT
    1 AS [C1],
    [Extent1].[ProsDocId] AS [ProsDocId],
    [Extent1].[ProsDocTypeId] AS [ProsDocTypeId],
    [Extent2].[DocTypeId] AS [DocTypeId],
    FROM  [dbo].[ProsDocs] AS [Extent1]
    INNER JOIN [dbo].[DocType] AS [Extent2] ON [Extent1].[ProsDocTypeId] = [Extent2].DocTypeId]

【讨论】:

  • 这正是我的问题。正如我的模型所示,Document 的主键是ProsDocId。关系应该在Document.TypeIdDocType.Id之间,或者换句话说,dbo.Document是主体,而dbo.DocType.DocTypeId是外键。请参阅我更新的问题。
  • @StephenCollins,我认为您对一对一关系的定义感到困惑,在这种关系中,正如您所说(文档是主体),主体不能 有另一列引用依赖,如Document.TypeIdDocType.Id,关系应该在Document.IdDocType.Id 之间,请检查this one to one relationship 其中Customer 表(主体)不能有像CustomerDetailId这样的另一列,我的答案还是一样,只需添加实体和查询
  • 无论我的措辞是否不正确,这个答案仍然不能解决我的问题。我需要将生成的查询作为我的问题中的第一个查询(“理想查询”)。该查询正是我将在自定义 SQL 中执行的;我需要 Linq 中的等价物。
  • @StephenCollins,我又更新了,你需要的是一对多
  • 是的,您的更新答案正是我所需要的。这对我来说有点“倒退”,所以我什至没有想到。不过,这绝对是正确的。谢谢!
猜你喜欢
  • 2013-08-18
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多