【问题标题】:EF 6 optional FK , delete still produces errorEF 6 可选 FK ,删除仍然产生错误
【发布时间】:2015-05-23 01:22:40
【问题描述】:

所以我有这两个简单的模型

public class Blog
{
    public int BlogId { get; set; }

    private string _Name;
    [Column("sNameColumn")]
    public string Name { get { return _Name; } set { _Name = value; } }

    public  virtual List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int? blog_id { get; set; }

    [ForeignKey("blog_id")]
    public virtual Blog Blog { get; set; }
}

我没有在 dbContext 定义中做任何不寻常的事情。然后,我尝试做这样的事情。

 db.Blogs.Remove(db.Blogs.Find(2)); 
 db.SaveChanges();

我收到一个 FK 违规错误。请注意,FK blog_id 可以为空,所以我认为 EF 应该处理删除,并使相应的 FK 为空。 你能告诉我我错过了什么吗?

【问题讨论】:

  • 仅仅因为 FK 列可以为空并不意味着 EF 会在您删除博客条目时将其取消。

标签: entity-framework foreign-key-relationship sql-delete


【解决方案1】:

必须加载实体,EF 才能处理将其外键设置为 null。

var b = db.Blogs.Find(2);
db.Entry(b).Collection(b => b.Posts).Load();
db.Blogs.Remove(b); 
db.SaveChanges();

【讨论】:

  • 感谢您的回复。是否有任何解决方法可以在不显式加载集合的情况下实现此行为?
  • 另外,假设 Post 有另一个可选的 fk 引用(例如 Comment)。我是否也必须懒惰地加载“评论”集合(如链)?
  • 如果Post有其他引用,如果不影响删除Blog,则不需要加载。如果有多个关系与Blog 的可选引用,那么您将必须加载所有这些关系;并且对于多个关系,使用多个Includes 和Single 优于FindLoad
  • 也就是说,你说如果我有多个关系,急切加载是最合适的方法吗?你能证明这一点吗?
  • (您是在询问急切加载而不是显式加载?)通常会更好,因为每次调用 Load 都会执行一次数据库查询,但多次调用 Include 会组合成一个查询。另一方面,您不能将IncludeFind 一起使用,因为Find 在上下文中查找并且可能根本不会向数据库发送请求。可能还有其他考虑因素。
【解决方案2】:

请记住,Entity Framework 只能更新它已加载的实体。

当然有一些方法可以通过原始 SQL 语句更新数据库记录,也可以通过 EF 执行,但这不是 EF 作为 ORM 的核心。

因此,如果您只想使用 EF,则别无选择。您必须在Blogs 中明确加载集合,以便它们与父级分离。比如Include:

var b = db.Blogs.Include(b => b.Posts).Include(b => b.Comments)
          .Single(b => b.BlogId == 2);
db.Blogs.Remove(b); 
db.SaveChanges();

Load 与其他答案一样。

另一种选择是使用Entity Framework Extented。它的功能之一是批量更新,它允许在给定模板记录的情况下一次性更新IQueryable 中的记录语句。这看起来像这样:

using EntityFramework.Extensions;
...
db.Posts.Where(p => p.BlogId == 2)
        .Update(p => new Post { BlogId = default(int?) });
db.Blogs.Remove(b); 
db.SaveChanges();

仅修改模板记录中设置的属性。要使此事务具有事务性,您应该将所有语句包装在 TransactionScope 中。

【讨论】:

  • 完全忘记了急切加载,感谢上帝存在
猜你喜欢
  • 1970-01-01
  • 2018-09-21
  • 2017-05-16
  • 1970-01-01
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
相关资源
最近更新 更多