为什么在更新现有实体时会获得实体的副本?

时间:2015-01-24 23:28:04

标签: c# entity-framework code-first

我将一些数据保存到我的数据库中,我首先使用代码。一切正常,直到我想要改变一个实体。例如:我向数据库中添加了四个人,当我更新其中一个人时,数据库会添加所有人的重复项。

更新 问题出在这段代码中:

Conversation newConv = new Conversation { Name = chatPerson.Name };
        newConv.Members.Add(person);
        newConv.Members.Add(chatPerson);

Conversation有一个Members列表,当我尝试将Members添加到列表中时,我会在数据库中获取副本。

旧帖子

我做的第一件事就是加载一个人:

var person = repo.GetWholePerson(3);

返回此人的代码:

public Person GetWholePerson(int id)
    {
        return _ctx.Persons
            .Include(a => a.Colleagues)
            .Include(a => a.Conversations)
            .FirstOrDefault(p => p.Id == id);
    }

以下是保存到数据库的代码:

using (Repository<Person> repo = new Repository<Person>())
    {
       var per = repo.Get(person.Id);
       var chatPer = repo.Get(chatPerson.Id);

       per.Conversations.Add(newConv);
       chatPer.Conversations.Add(newConv);

       repo.Update(per);
       repo.Update(chatPer);
    }

以下是存储库中的代码:

public void Update(T entity)
    {
        dbSet.Attach(entity);
        _ctx.Entry(entity).State = EntityState.Modified;
        _ctx.SaveChanges();
    }

人员类:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public byte[] Image { get; set; }

    public virtual ICollection<Conversation> Conversations { get; set; }

    public virtual ICollection<Person> Colleagues { get; set; }
    public virtual ICollection<Person> Test { get; set; }


    public Person()
    {
        Conversations = new List<Conversation>();
        Colleagues = new List<Person>();
        Test = new List<Person>();
    }
}

会话课程:

public class Conversation
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Message> Messages { get; set; }
    public virtual ICollection<Person> Members { get; set; }

    public Conversation()
    {
        Messages = new List<Message>();
        Members = new List<Person>();
    }
}

一切正常!但是当我连接到我的数据库时,有四个新人。 =(

1 个答案:

答案 0 :(得分:0)

不要调用Attach方法,它会将实体标记为Unchanged状态,这意味着它已附加到上下文后没有更改。假定您附加的对象存在于数据库中。 Attach()对于更新以下场景中的实体非常有用:

using (var context = new MyDbContext())
{
   context.Attach(person);
   person.Name = "Bob";
   context.SaveChanges();
}

如果您知道某个实体已经存在于数据库中,并且您希望保存之前所做的所有更改,只需调用Entry方法修改实体状态:

public void Update(T entity)
{
    _ctx.Entry(entity).State = EntityState.Modified;
    _ctx.SaveChanges();
}

当您将状态更改为Modified时,实体的所有属性都将标记为已修改,并且在调用SaveChanges时,所有属性值都将发送到数据库。

事实上,如果您使用相同的repo实例来获取和修改您的实体,我认为您甚至不需要调用Entry方法,只需调用{ {1}}方法。

如果您想了解更多如何使用这些方法,请查看此link