Entity framework 实体框架:一对零或与主体上的外键的一种关系
我有一个1:0..1的关系,我想使用fluent API与EF 6进行映射。该关系由一个主体组成,主体可以有也可以没有从属关系。依赖者必须始终有一个主体 在principal中,我需要访问受抚养人的Id 我的代码如下所示:Entity framework 实体框架:一对零或与主体上的外键的一种关系,entity-framework,ef-code-first,entity-framework-6,entity-framework-migrations,Entity Framework,Ef Code First,Entity Framework 6,Entity Framework Migrations,我有一个1:0..1的关系,我想使用fluent API与EF 6进行映射。该关系由一个主体组成,主体可以有也可以没有从属关系。依赖者必须始终有一个主体 在principal中,我需要访问受抚养人的Id 我的代码如下所示: public class Principal { public int Id {get; private set; } public int? DependentId { get; private set; } public virtual Depe
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();
}
}
我的映射如下所示:
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();
}
}
如您所见,列DEPENDENTID
不是外键。运行程序并将从属对象与主体关联时,DependentId属性保持为空,即EF无法识别它与从属对象本身相关
我做错了什么?是的,这很棘手,而且在我看来是一个EF错误。我使用的解决方法是伪1:M:
HasRequired(x => x.Principal)
.WithMany()
.HasForeignKey(x => x.DependentId);
.WillCascadeOnDelete();
在DependentMap中,您声明字段DEPENDENTID为数据库生成(标识)的依赖表的主键,因此它永远不会是外键。您不能随意更改它(使其指向您选择的实体) 此外,对于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();
}
}
(我省略了级联删除,但也应该清楚)
E/R模型为正常形式(并且是唯一适用于EF的模型)。顺便说一句,如果访问
Principal.Dependent
property,EF将生成一个类似于selected*from Dependent的查询,其中PRINCIPALID=
where是主体实体的id,因此它真正起作用
现在,关于您的需求,要从主体访问Dependent.Id,唯一的方法是dependentId=Principal.Dependent.Id
(或者更好的方法是dependentId=Principal.Dependent==null?null:Principal.Dependent.Id
)
如果您真的想为主体上引用依赖表的外键创建一个字段,该怎么办?此模型不是正常形式,因此EF将不会处理它(对于DBMS,您也需要编写触发器来处理它)。
我的意思是,在R-DBMS中没有一个约束,您可以指定如果列DEPENDENT.PRINCIPALID引用主体,那么列PRINCIPAL.DEPENDENTID也应该引用原始的依赖项。
在这种情况下,您需要自己处理PRINCIPAL.DEPENDENTID(即主体实体必须具有DEPENDENTID属性,您必须自己处理,并且EF在导航期间不使用该属性) 尝试仅在一个配置文件中设置
主体
/依赖关系。@krillgar我已经尝试过了,运气不好。你能给我一个代码示例吗?如果主体被配置为“有许多”依赖项,主体怎么能持有依赖项的外键?另外,代码没有编译:.HasForeignKey(x=>x.DependentId)
需要Dependent
类的属性,但是DependentId
显然是主体
类的属性感谢您非常清楚的回答。我希望主体上有依赖id的真正原因是,每次选择主体时,我都需要知道是否存在依赖id。因为这些选择是频繁的,我想让它们保持快速。因此我认为最好将DependentId
作为Principal
上的字段,而不是Principal.Dependent.Id
,因为后者需要一个连接。当然,我给出的例子是简化的,实际上我有许多不同的依赖属性(每个属性都有自己的表),对于每个属性,我需要知道它是否存在。我理解这个问题。在这种情况下,您需要自己以某种方式(即在数据库上使用触发器并将列设置为数据库生成的列、覆盖savechanges或使用其他技术)来处理DependentId。我不知道您的要求,但您也可以评估在主体表中插入所有字段和/或使用ComplexType(类似于使用更干净的模型在主体表中插入所有字段)和/或使用继承(通常1-1关系与继承相关;如果使用TPH,结果类似于插入主体表中的所有字段)。