EF代码优先 - 无法更新数据库行

3

我正在尝试使用EF“代码优先”方法编写一些代码,遇到了一个奇怪的问题。

我的数据上下文:

    public class BookmarkerDataContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>().HasKey(u => u.UserId);
            base.OnModelCreating(modelBuilder);
        }
     }

用户对象的位置:

   public class User
    {
        public long UserId { get; set; }
        public ICollection<Tag> Tags { get; set; }
    }

在我的代码中,我正在做一些非常简单的事情:

public void UpdateUserTags(User user,ICollection<Tag> taglist)
    {
        user.Tags = new List<Tag>(user.Tags.Union(taglist));
        datacontext.Users.Add(user);
        datacontext.SaveChanges();
    }

我将传递给此函数的用户对象是以下内容的结果:

类似于以下内容:

datacontext.Users.SingleOrDefault(u => u.UserId==id)

每次我调用UpdateUserTags函数时,似乎会在用户表中创建一个新行而不是更新它。我在这里做错了什么吗?
4个回答

4

@Donald是正确的,当进行更新时,您需要Attach到ObjectContext。

但是,这仅适用于您的实体已分离的情况。

如果您已经从图形中检索到了单个实体,则听起来像是:

var user = datacontext.Users.SingleOrDefault(u => u.UserId==id);

这意味着您不需要再次附加或获取它。只需执行以下操作:
var user = datacontext.Users.SingleOrDefault(u => u.UserId==id);
user.Tags = new List<Tag>(user.Tags.Union(taglist));
context.SaveChanges();

然而,我不建议替换整个标签集合,而是添加标签:

user.Tags.Add(someTag);

HTH


3
我认为您想将对象与数据上下文关联,而不是添加它。请参考Attach
public void UpdateUserTags(User user,ICollection<Tag> taglist)
{
    datacontext.Attach(user);
    user.Tags = new List<Tag>(user.Tags.Union(taglist));
    datacontext.SaveChanges();
}

一旦它被附加,上下文就会意识到这个对象。一旦您保存更改,它们应该被持久化到数据库中。


0

这与您的特定问题无关,但对于惰性加载,您需要将标签标记为虚拟

public virtual ICollection<Tag> Tags { get; set; }

此外,看起来您正在尝试为用户添加新标签(或更新其标签),如果是这种情况,那么您将需要使用Donald建议的Attach功能。


virtual 关键字与延迟加载无关。virtual 关键字与更改跟踪有关(EF 将创建一个代理类,覆盖所有成员)。 - RPM1984
你说得对,这是我的错,今天过得很长。谢谢指出我的错误 ;) - PsychoCoder

0

这行不会

datacontext.Users.Add(user);

始终将用户记录标记为需要添加到用户表中。

我认为您必须将用户从旧上下文中分离并附加到新上下文中,以便能够正确更新记录。 但我不是EF专家,所以可能会有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接