实体框架 – 实体框架:与主体上的外键一对一或零关系

我有一个1:0..1的关系,我想用EF 6使用流畅的API进行映射.该关系由一个委托人组成,该委托人可能有也可能没有受抚养人.依赖者必须始终拥有委托人.

在校长中,我需要访问依赖项的Id.

我的代码看起来像这样:

public class Principal
{
    public int Id {get; private set; }

    public int? DependentId { get; private set; }
    public virtual Dependent Dependent { get; private set; }
}

public class Dependent
{
    public int Id { get; private set; }

    public virtual Principal Principal { get; private set; }
}

我的映射看起来像这样:

    public class PrincipalMap : EntityTypeConfiguration<Principal>
    {
        public PrincipalMap()
        {
            ToTable("PRINCIPALS");

            HasKey(x => x.Id);

            Property(x => x.Id)
                .HasColumnName("PRINCIPALID")
                .IsRequired()
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            Property(x => x.DependentId)
                .HasColumnName("DEPENDENTID")
                .IsOptional();
        }
    }

    public class DependentMap : EntityTypeConfiguration<Dependent>
    {
        public DependentMap()
        {
            ToTable("DEPENDENTS");

            HasKey(x => x.Id);

            Property(x => x.Id)
                .HasColumnName("DEPENDENTID")
                .IsRequired()
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            HasRequired(x => x.Principal).WithOptional(x => x.Dependent).Map(x => x.MapKey("PRINCIPALID")).WillCascadeOnDelete();
        }
    }

这导致以下迁移:

            CreateTable(
                "dbo.PRINCIPALS",
                c => new
                    {
                        PRINCIPALID = c.Int(nullable: false, identity: true),
                        DEPENDENTID = c.Int(),
                    })
                .PrimaryKey(t => t.PRINCIPALID);

            CreateTable(
                "dbo.DEPENDENTS",
                c => new
                    {
                        DEPENDENTID = c.Int(nullable: false, identity: true),
                        PRINCIPALID = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.DEPENDENTID)
                .ForeignKey("dbo.PRINCIPALS", t => t.PRINCIPALID, cascadeDelete: true)
                .Index(t => t.PRINCIPALID);

如您所见,DEPENDENTID列不是外键.当运行程序并将依赖对象与主体相关联时,DependentId属性保持为空,即EF不识别它与依赖本身相关.

我究竟做错了什么?

最佳答案 在DependentMap中,您将字段DEPENDENTID声明为DEPENDENT表的主键,数据库生成(标识),因此它永远不会是外键.您无法根据需要更改它(使其指向您选择的实体).

此外,使用EF(和E / R),您不需要两列(每个表一列)具有1-0..1的关系.您只能有一列(不可为空).

在您的情况下,此模型应该工作:

public class Principal
{
    public int Id { get; private set; }

    public virtual Dependent Dependent { get; private set; }
}

public class Dependent
{
    public int Id { get; private set; }

    public virtual Principal Principal { get; private set; }
}

public class PrincipalMap : EntityTypeConfiguration<Principal>
{
    public PrincipalMap()
    {
        ToTable("PRINCIPALS");

        HasKey(x => x.Id);

        Property(x => x.Id)
            .HasColumnName("PRINCIPALID")
            .IsRequired()
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

public class DependentMap : EntityTypeConfiguration<Dependent>
{
    public DependentMap()
    {
        ToTable("DEPENDENTS");

        HasKey(x => x.Id);

        Property(x => x.Id)
            .HasColumnName("DEPENDENTID")
            .IsRequired()
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        HasRequired(x => x.Principal).WithOptional(x => x.Dependent).Map(x => x.MapKey("PRINCIPALID")).WillCascadeOnDelete();
    }
}

在这种情况下,表创建stataments(由EF提供​​程序生成)应该类似于

ExecuteNonQuery==========
CREATE TABLE [DEPENDENTS] (
 [DEPENDENTID] int not null identity(1,1)
, [PRINCIPALID] int not null
);
ALTER TABLE [DEPENDENTS] ADD CONSTRAINT [PK_DEPENDENTS_204c4d57] PRIMARY KEY ([DEPENDENTID])
ExecuteNonQuery==========
CREATE TABLE [PRINCIPALS] (
 [PRINCIPALID] int not null identity(1,1)
);
ALTER TABLE [PRINCIPALS] ADD CONSTRAINT [PK_PRINCIPALS_204c4d57] PRIMARY KEY ([PRINCIPALID])
ExecuteNonQuery==========
CREATE INDEX [IX_PRINCIPALID] ON [DEPENDENTS] ([PRINCIPALID])
ExecuteNonQuery==========
ALTER TABLE [DEPENDENTS] ADD CONSTRAINT [FK_DEPENDENTS_PRINCIPALS_PRINCIPALID] FOREIGN KEY ([PRINCIPALID]) REFERENCES [PRINCIPALS] ([PRINCIPALID])

(我在级联删除时省略,但也应该清楚).

E / R模型是正常形式(并且是唯一适用于EF的模型).
顺便说一句,如果您访问Principal.Dependent属性,EF将生成类似于从依赖的selected *的查询,其中PRINCIPALID =< principal_id>其中是主要实体的id,所以它确实有效.

现在,关于您的要求,从Principal访问Dependent.Id的唯一方法是dependentId = Principal.Dependent.Id(或者,更好的是,dependentId = Principal.Dependent == null?null:Principal.Dependent.Id).

如果你真的想要PRINCIPAL上涉及DEPENDENT表的外键的字段怎么办?
此模型不是正常形式,因此EF不会处理它(也需要DBMS,您需要编写触发器来处理它).
我的意思是,在R-DBMS中没有约束,您可以指定如果列DEPENDENT.PRINCIPALID引用PRINCIPAL,则列PRINCIPAL.DEPENDENTID应引用原始的DEPENDENT.
在这种情况下,您需要做的是自己处理PRINCIPAL.DEPENDENTID(即,Principal实体必须具有您必须自己处理的DEPENDENTID属性,并且在导航期间不会被EF使用).

点赞