6

我有 2 个 POCO 课程(如下)并希望删除他们的两个记录之间的链接。根据这个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; }
}

编辑:这是上述链接文章中似乎与我看到的功能不一致的特定行:

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

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

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

4

2 回答 2

6

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

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);
        }
    }
}
于 2013-01-27T05:35:37.907 回答
1

编辑:

我刚刚通读了评论(我可能应该先阅读它们,但我已经写了这个,所以我会留下它),看到你们得出了一个非常相似的结论,希望这仍然有助于解释一些原因。另外在旁注中,我认为您最好使用 FK id 属性来使关系为空(如果它可用),因为这意味着您根本不必实际加载远程实体。


嘿,所以我认为这是怎么回事:

你加载你的计算机实体

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

您将 User 属性设置为 null

  • 跟踪图仍设置为 null,因此无法区分您的故意 null 和未加载的 null

您保存更改

  • 跟踪器检查初始图,发现您尚未加载用户属性并将 null 视为未加载的初始状态
  • 没有保留任何更改

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

  1. 在将关系设置为 null之前强制加载用户,您可以通过在启用延迟加载时访问它来执行此操作,或者在查询中使用 .Include 语法。
  2. 将 UserId 属性设置为 null

第二个更容易,并且应该可以工作,因为用户 ID 属性不在远程实体上。EF 会将 null nav 属性或 null FK 视为更改并执行删除。

于 2013-01-25T06:21:36.420 回答