为什么EF核心尝试将导航属性添加到DB中,而不仅是外国模型的ID?

时间:2019-05-14 16:10:55

标签: asp.net-core entity-framework-core

我想知道为什么英孚试图增加外国模型。 示例:

public class Category
{
    public int Id { get; set; }
    public string Name{ get; set; }
}

public class Content
{
    public int Id { get; set; }
    public string Name{ get; set; }
    public Category Category{ get; set; }
}

使用迁移创建“内容”后,我有了一个包含类别ID的表。那是创造。因此,我有三列:Id,名称和categoryId。似乎EF“知道”这应该只是需要存储的Category的主键。

比起我,我尝试用EF添加一些东西。

var cat = new Category {Id = 2, Name = "awesomeCat"})
var addContent = new Content({Name = "test", Category = cat})

现在,我想使用_context.Add(addContent)添加内容。我期望向数据库中插入一个使用名称“ test”和categoryId 2的插入。ID将由DB生成。

但是相反,EF也尝试将新的类别添加到类别表中。

因此,我进行了更深入的研究,似乎EF“不”知道它已经存在并且没有维护有关类别模型的任何事务。 我再次尝试,不使用新类别,而是在之前加载它:     var cat = _context.findById(“ 2”); 并分配了这个。现在,EF应该知道该目录已经存在,不必将其添加到类别表中。

可能是我的模型是错误的。 我是否需要像这样使用它?

public class Content
{
    public int Id { get; set; }
    public string Name{ get; set; }
    public int? CategoryId{ get; set; }
    [ForeignKey("CategoryId")]
    public Category Category{ get; set; }
}

那我不会得到两个类别引用吗?

2 个答案:

答案 0 :(得分:0)

您需要告诉EF Core这是主密钥并生成密钥

public class Category
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Content
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public Category Category { get; set; }
}

然后,您无需标记[ForeignKey(“ CategoryId”)],EF Core会将对象引用转换为数据库中的ID

如果我误解了您的问题,请再问一次:)

答案 1 :(得分:0)

EF Core具有对实体的内部跟踪。当您仅新建类别时,就不会对其进行跟踪。添加内容时,EF还将跟踪所有相关实体,其中包括您的类别,默认情况下将被跟踪为“已添加”。您有几种选择。

  1. 不要“新建”现有的类别,而是从数据库中检索它。如果EF从数据库中将其提取,则会对其进行跟踪,并且不会再次添加。

  2. 您可以显式跟踪您新建的类别实例,并将其状态设置为“未更改”。

    _context.Attach(category);
    _context.Entry(category).State = EntityState.Unchanged;
    _context.Add(content);
    
  3. 最好的方法是根本不处理引用属性,而使用显式外键属性。向您的内容类添加属性:

    public int CategoryId { get; set; }
    

    然后,您只需设置此ID,即可代替Category道具:

    var addContent = new Content { Name = "test", CategoryId = 2 };
    

    保存后,EF将回填引用属性。