Entity framework 删除导航属性不会导致';t更新数据库
我有2个POCO类(如下),希望删除它们两个记录之间的链接。根据EF 5.0,应能够在不加载用户类的情况下处理删除,如下所示:Entity framework 删除导航属性不会导致';t更新数据库,entity-framework,entity-framework-5,Entity Framework,Entity Framework 5,我有2个POCO类(如下),希望删除它们两个记录之间的链接。根据EF 5.0,应能够在不加载用户类的情况下处理删除,如下所示: context.Computers.Find("test").User = null; context.SaveChanges(); 这不起作用,但使用.net 4认可的方法可以起作用: en = context.Computers.Find("test"); context.Entry(en).Reference(e => e.User).Load(); en
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; }
}
从基于.NET 4.5的Entity Framework 5.0开始,您可以在不加载相关端的情况下将关系设置为null。编辑:
我只是通读了这些评论(我可能应该先读,但我已经写了,所以我就不写了),看到你们得出了一个非常相似的结论,希望这仍然有助于解释为什么。另一方面,我认为最好使用FK id属性使关系为空(如果可用),因为这意味着您根本不必实际加载远程实体
嘿,我想这就是发生的事情: 正在加载计算机实体
- 此时,用户导航属性为空
- 跟踪图将此实体的初始状态设置为null
- 跟踪图仍然设置为null,因此无法区分有意设置的null和尚未加载的null之间的差异
- 跟踪器检查初始图,发现您尚未加载用户属性,并将null视为未加载的初始状态
- 不会保留任何更改
第二种方法简单得多,应该可以工作,因为用户ID属性不在远程实体上。EF将把空nav属性或空FK视为更改并执行删除。您看不到正在删除的关系,因为您的代理不是更改跟踪代理,而只是延迟加载代理。要使其成为更改跟踪代理,需要将所有属性设置为虚拟。下面请查找一个示例,该示例在不首先加载导航属性的情况下重置导航属性。现在的问题是是否使用更改跟踪代理-请参阅,因为它包含了一个关于此的有趣讨论
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);
}
}
}
公共类计算机
{
公共虚拟字符串Id{get;set;}
公共虚拟可空用户标识{get;set;}
公共虚拟用户用户{get;set;}
}
公共类用户
{
公共int Id{get;set;}
公共虚拟ICollection计算机{get;set;}
}
公共类MyContext:DbContext
{
公共数据库集计算机{get;set;}
公共数据库集用户{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
使用(var ctx=new MyContext())
{
如果(!ctx.Computers.Any())
{
var user=ctx.Users.Add(new user());
添加(newcomputer(){Id=“MyComputer”,User=User});
ctx.SaveChanges();
}
}
使用(var ctx=new MyContext())
{
var computer=ctx.Computers.Single();
computer.User=null;
ctx.SaveChanges();
}
使用(var ctx=new MyContext())
{
var computer=ctx.Computers.Include(“用户”).Single();
Console.WriteLine(computer.User==null);
}
}
}
你是说context.Computers
而不是context.Users
和…Find(“test”)。UserId=null
而不是…查找(“测试”)。User=null代码>?用户上的是(我已进行了更新)。对于…查找(“测试”)。User=null;这是正确的。我正在将导航属性设置为null,以便取消用户与计算机的链接。您是否禁用了延迟加载或代理创建?您的第一行依赖于启用延迟加载,否则它将无法工作。但是,通过延迟加载,它将加载用户
——这与您的预期相反。如果您不想这样做,请将UserId
设置为null
@Slauma-LazyLoadingEnabled和ProxyCreationEnabled都设置为true。我不关心加载用户
和更新用户ID
,相反,这是可行的,但是能够通过导航属性删除关系会容易得多,特别是对于复合键关系。啊,我明白了。在代码或调试器中检查属性时,可以调用User
的属性getter。这会触发延迟加载。但是上面的第一行只调用属性setter,因此不会发生延迟加载。无论如何,我建议使用eager加载context.Computers.Include(“用户”).SingleOrDefault(c=>c.Id==“test”).User=null代码>这应该可以工作,并将为您节省一次数据库往返。啊哈!谢谢你的澄清。这在EF5/.NET4.5中是一种新的行为吗?在.NET4.0中不是这样吗?问题中链接的文章是这样说的,但实际上使用的是没有更改跟踪代理的模型。@pawel你确定这是新的吗?我认为这是从EF 4.1开始的。@EF6之前版本的LukeMcGregor代理是在System.Data.Entity.dll内部生成的,而不是在EntityFramework.dll内部生成的。由于.NET Framework 4.5是一个就地更新,如果您在带有.NET Framework 4.5的框中使用EF4.1,您可以在EF4.1中看到这一点。简言之,它取决于机箱上的.NET Framework,而不是EntityFramework的OOB(带外)版本。
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);
}
}
}