Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 删除导航属性不会导致';t更新数据库_Entity Framework_Entity Framework 5 - Fatal编程技术网

Entity framework 删除导航属性不会导致';t更新数据库

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

我有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.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之间的差异
保存更改

  • 跟踪器检查初始图,发现您尚未加载用户属性,并将null视为未加载的初始状态
  • 不会保留任何更改
在我看来,如果是这种情况,有两种不同的方法可以让EF将其检测为更改(从而删除您的关系):

  • 强制加载用户在将关系设置为null之前,可以通过在启用延迟加载时访问该关系,或者在查询中使用.Include语法来执行此操作
  • 将UserId属性改为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);
            }
        }
    }