删除导航属性不会更新数据库

时间:2013-01-24 19:54:32

标签: entity-framework entity-framework-5

我有2个POCO课程(如下),并希望删除他们的两个记录之间的链接。根据{{​​3}} EF 5.0应该能够处理删除而不加载User类,如下所示:

context.Computers.Find("test").User = null;
context.SaveChanges();

这不起作用,但使用.net 4批准的方法可以使用:

en = context.Computers.Find("test");
context.Entry(en).Reference(e => e.User).Load();
en.User = null;
context.SaveChanges();

我的EF参考是EntityFramework.dll版本5.0.0.0。我错过了一些明显的东西吗?

以下是课程:

public class Computer
{
    public string Id { get; set; }
    public Nullable<int> UserId { get; set; }
    public virtual User User { get; set; }
}
public class User
{
    public int Id { get; set; }
    public virtual ICollection<Computer> Computers { get; set; }
}

编辑:以上链接文章中的具体行似乎与我看到的功能不一致:

要删除关系,请将navigation属性设置为null。如果您正在使用基于.NET 4.0的实体框架,则需要在将其设置为null之前加载相关的结尾。例如:

context.Entry(course).Reference(c => c.Department).Load();
course.Department = null;

从基于.NET 4.5的Entity Framework 5.0开始,您可以将关系设置为null,而不加载相关的结尾。

2 个答案:

答案 0 :(得分:6)

您没有看到关系被删除,因为您的代理不是更改跟踪代理,而只是延迟加载代理。要使其成为更改跟踪代理,您需要将所有属性设置为虚拟。下面是一个重置导航属性而不先加载它的例子。现在的问题是是否使用更改跟踪代理 - 请参阅this post,因为它包含有关此问题的有趣讨论。

public class Computer
{
    public virtual string Id { get; set; }
    public virtual Nullable<int> UserId { get; set; }
    public virtual User User { get; set; }
}

public class User
{
    public int Id { get; set; }
    public virtual ICollection<Computer> Computers { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Computer> Computers { get; set; }
    public DbSet<User> Users { get; set; } 
}

class Program
{
    static void Main(string[] args)
    {
        using (var ctx = new MyContext())
        {
            if (!ctx.Computers.Any())
            {
                var user = ctx.Users.Add(new User());
                ctx.Computers.Add(new Computer() { Id = "MyComputer", User = user });
                ctx.SaveChanges();
            }
        }

        using (var ctx = new MyContext())
        {
            var computer = ctx.Computers.Single();
            computer.User = null;
            ctx.SaveChanges();
        }

        using (var ctx = new MyContext())
        {
            var computer = ctx.Computers.Include("User").Single();
            Console.WriteLine(computer.User == null);
        }
    }
}

答案 1 :(得分:1)

修改

我只是阅读了评论(我可能应该首先阅读它们,但我已经写了这么多病了)并且看到你们得出了一个非常相似的结论,希望这仍然有助于解释一些原因。另外在旁注中我认为你最好使用FK id属性来取消关系,如果它可用,因为这意味着你根本不需要实际加载远程实体。


嘿所以我认为这是最新进展的:

您正在加载计算机实体

  • 此时用户导航属性为空
  • 跟踪图将此实体的初始状态设置为null

您将User属性设置为null

  • 跟踪图仍然设置为null,因此无法说明故意null和not-loaded-yet null之间的区别

您保存更改

  • 跟踪器检查初始图,看到你还没有加载用户属性并将null视为卸载初始状态
  • 不会保留任何更改

如果是这种情况,我认为有两种不同的方法可以让EF将此检测为更改(从而删除您的关系):

  1. 在将关系设置为null之前强制加载用户,您可以通过在启用延迟加载时访问它,或在查询中使用.Include语法来执行此操作。
  2. 将UserId属性设置为null
  3. 第二个更容易,因为用户ID属性不在远程实体上,所以应该工作。 EF会将null nav属性或null FK视为更改并执行删除。