C# 实体框架-未设置外键(0/null),但导航属性不为null
我在这个问题上纠缠了很长时间。我首先使用Fluent API代码来设计数据库(EF 6.1)。问题是,当我添加一个新对象时,我可以通过其导航属性访问该对象中的实体,但FK为0或NULL(分别为必选和可选)。他们是一对一的关系,我尝试了双向和单向 以下是代码的一部分(简化了,但只包含较少的实体): 我真的被这件事难住了。我尝试过改变很多东西,使数据库平坦化,只使用数据注释,浪费了很多时间。希望有人能帮忙:)。非常感谢 编辑I:因此,在调试期间,当创建对象时,C# 实体框架-未设置外键(0/null),但导航属性不为null,c#,.net,entity-framework,C#,.net,Entity Framework,我在这个问题上纠缠了很长时间。我首先使用Fluent API代码来设计数据库(EF 6.1)。问题是,当我添加一个新对象时,我可以通过其导航属性访问该对象中的实体,但FK为0或NULL(分别为必选和可选)。他们是一对一的关系,我尝试了双向和单向 以下是代码的一部分(简化了,但只包含较少的实体): 我真的被这件事难住了。我尝试过改变很多东西,使数据库平坦化,只使用数据注释,浪费了很多时间。希望有人能帮忙:)。非常感谢 编辑I:因此,在调试期间,当创建对象时,XmlDocId和OtherXmlDoc
XmlDocId
和OtherXmlDocId
为0/null,这是合乎逻辑的,因为它们尚未添加到各自的表中,因此没有Id。但是,据我所知,当我调用SaveChanges()
EF自动检测并应用所有更改,这将更新FK()
EDIT II:问题的“解决方法”是在调用
SaveChanges()
后显式设置FK(Template.XmlDocId=Template.XmlDocId
),但这当然不是我想要的解决方案。我使用EF来抽象这些手动操作,并为我处理所有这些操作。查看明确提及外键是否有帮助:
public class Template
{
public int Id { get; set; }
public int XmlDocId{ get; set; }
[ForeignKey("XmlDocId")]
public virtual XmlDoc XmlDoc { get; set; }
public int? OtherXmlDocId{ get; set; }
[ForeignKey("OtherXmlDocId")]
public virtual OtherXmlDoc OtherXmlDoc { get; set; }
}
在您的
一对一
关系中,模板
是主体,而XmlDoc
和其他XmlDoc
是从属关系。这意味着Template
没有外键,但相反,XmlDoc
/OtherXmlDoc
中的PKId
列也是模板的FK。因此,XmlDocId
和OtherXmlDocId
列在关系中不起任何作用,EF将它们视为常规数据列,并且不会将它们与导航属性同步
简而言之,它们是多余的,您只需删除它们并使用导航属性(在SaveChanges
之后,非空导航属性的Id
将始终与entity.Id
相同)。另外,添加反向导航属性也很好,因此最终的模型/设置可能是这样的
public class Template
{
public int Id { get; set; }
public virtual XmlDoc XmlDoc { get; set; }
public virtual OtherXmlDoc OtherXmlDoc { get; set; }
}
public class XmlDoc
{
public int Id { get; set; }
[Required]
public string RawXml { get; set; }
public virtual Template Template { get; set; }
}
public class OtherXmlDoc
{
public int Id { get; set; }
[Required]
public string RawXml { get; set; }
public virtual Template Template { get; set; }
}
private void ConfigureTemplates(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Template>()
.HasRequired<XmlDoc>(t => t.XmlDoc)
.WithRequiredPrincipal(d => d.Template)
.WillCascadeOnDelete(true);
modelBuilder.Entity<Template>()
.HasOptional<OtherXmlDoc>(t => t.OtherXmlDoc)
.WithOptionalPrincipal(d => d.Template)
.WillCascadeOnDelete(true);
}
公共类模板
{
公共int Id{get;set;}
公共虚拟XmlDoc XmlDoc{get;set;}
公共虚拟OtherXmlDoc OtherXmlDoc{get;set;}
}
公共类XmlDoc
{
公共int Id{get;set;}
[必需]
公共字符串RawXml{get;set;}
公共虚拟模板模板{get;set;}
}
公共类XML文档
{
公共int Id{get;set;}
[必需]
公共字符串RawXml{get;set;}
公共虚拟模板模板{get;set;}
}
专用void配置模板(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasRequired(t=>t.XmlDoc)
.WithRequiredPrincipal(d=>d.Template)
.WillCascadeOnDelete(真);
modelBuilder.Entity()
.has可选(t=>t.OtherXmlDoc)
.WithOptionalPrincipal(d=>d.Template)
.WillCascadeOnDelete(真);
}
模板表上的PK是否启用了自动递增功能?我没有明确设置它,但我假设它可以工作,因为我可以添加模板,并且它们的PK是正确的。您看过表了吗?在Templates
表中没有外键约束,我想这两个ID都被当作字段处理。你说得对。对于这些实体,表定义没有FK约束。但是,EF不应该根据*Id变量名自动推断这些字段为FK吗?()无论如何,我如何通过Fluent API或数据注释显式设置FK约束,以便检查这是否解决了它?通常会这样。但在这里,您得到了这一点,因为您配置关系的方式。事实上,其他表(PK)中的Id
列也是FK到Templates
table的。模板
表是关系的“所有者”(主体)。我不知道这是否是你的意图。就像“此文档仅用于此模板。删除模板删除单据。doc.Id与template.Id`.相同。我已经尝试过了,但它不起作用,也不起作用:'类型'template'的属性'XmlDoc'上的ForeignKeyAttribute无效。在依赖的“XmlDoc”上找不到外键名称“XmlDocId”。名称值应为以逗号分隔的外键属性名称列表。我将其更改为[ForeignKey(“Id”)]'
,这允许我对数据库进行种子设定,但在添加新数据时,它们的FK仍然为0/NULL。
public class Template
{
public int Id { get; set; }
public int XmlDocId{ get; set; }
[ForeignKey("XmlDocId")]
public virtual XmlDoc XmlDoc { get; set; }
public int? OtherXmlDocId{ get; set; }
[ForeignKey("OtherXmlDocId")]
public virtual OtherXmlDoc OtherXmlDoc { get; set; }
}
public class Template
{
public int Id { get; set; }
public virtual XmlDoc XmlDoc { get; set; }
public virtual OtherXmlDoc OtherXmlDoc { get; set; }
}
public class XmlDoc
{
public int Id { get; set; }
[Required]
public string RawXml { get; set; }
public virtual Template Template { get; set; }
}
public class OtherXmlDoc
{
public int Id { get; set; }
[Required]
public string RawXml { get; set; }
public virtual Template Template { get; set; }
}
private void ConfigureTemplates(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Template>()
.HasRequired<XmlDoc>(t => t.XmlDoc)
.WithRequiredPrincipal(d => d.Template)
.WillCascadeOnDelete(true);
modelBuilder.Entity<Template>()
.HasOptional<OtherXmlDoc>(t => t.OtherXmlDoc)
.WithOptionalPrincipal(d => d.Template)
.WillCascadeOnDelete(true);
}