EF6 Code First - 使用不匹配的外键配置一对一关系

时间:2014-09-03 15:51:19

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

我使用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 --> 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

1 个答案:

答案 0 :(得分:3)

如果Document是主体且DocType是依赖,那么您需要

  • Document

    上进行此配置
    HasRequired(d => d.DocType).WithRequiredPrincipal(dt => dt.Document);
    
  • DocType

    上的此配置
    HasRequired(dt => dt.Document).WithRequiredDependent(d => d.DocType);
    

并从TypeId移除ProsDocTypeId / Document属性,因为委托人不能将外键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; }
}

的LINQ:

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);

的LINQ:

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]