C# 实体框架-未设置外键(0/null),但导航属性不为null

C# 实体框架-未设置外键(0/null),但导航属性不为null,c#,.net,entity-framework,C#,.net,Entity Framework,我在这个问题上纠缠了很长时间。我首先使用Fluent API代码来设计数据库(EF 6.1)。问题是,当我添加一个新对象时,我可以通过其导航属性访问该对象中的实体,但FK为0或NULL(分别为必选和可选)。他们是一对一的关系,我尝试了双向和单向 以下是代码的一部分(简化了,但只包含较少的实体): 我真的被这件事难住了。我尝试过改变很多东西,使数据库平坦化,只使用数据注释,浪费了很多时间。希望有人能帮忙:)。非常感谢 编辑I:因此,在调试期间,当创建对象时,XmlDocId和OtherXmlDoc

我在这个问题上纠缠了很长时间。我首先使用Fluent API代码来设计数据库(EF 6.1)。问题是,当我添加一个新对象时,我可以通过其导航属性访问该对象中的实体,但FK为0或NULL(分别为必选和可选)。他们是一对一的关系,我尝试了双向和单向

以下是代码的一部分(简化了,但只包含较少的实体):

我真的被这件事难住了。我尝试过改变很多东西,使数据库平坦化,只使用数据注释,浪费了很多时间。希望有人能帮忙:)。非常感谢

编辑I:因此,在调试期间,当创建对象时,
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
中的PK
Id
列也是
模板的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);
}