实体框架 - 通过更改外键来更新关系

时间:2013-08-19 21:03:13

标签: c# entity-framework orm entity-framework-5 relational-database

我有以下两个模型和DbContext:

    public class TestDbContext : DbContext
    {
        public IDbSet<Person> People { get; set; }
        public IDbSet<Car> Cars { get; set; }
    }

    public class Person
    {
        public Person()
        {
            ID = Guid.NewGuid();
        }

        public Guid ID { get; set; }
        public string Name { get; set; }
        public virtual List<Car> Cars { get; set; }
    }

    public class Car
    {
        public Car()
        {
           ID = Guid.NewGuid();
        }

        public Guid ID { get; set; }
        public string Name { get; set; }
        public virtual Person Owner { get; set; }
    }

然后我宣布一个人员列表和一个汽车列表,将第一辆汽车的所有者设置为列表中的第一个人:

List<Person> People = new List<Person>()
        {
            new Person() {Name = "bill", ID = new Guid("6F39CC2B-1A09-4E27-B803-1304AFDB23E3")},
            new Person() {Name = "ben", ID = new Guid("3EAE0303-39D9-4FD9-AF39-EC6DC73F630B")}
        };

        List<Car> Cars = new List<Car>() { new Car() { Name = "Ford", Owner = People[0], ID = new Guid("625FAB6B-1D56-4F57-8C98-F9346F1BBBE4") } };   

我使用以下代码将其保存到数据库中,这样可以正常工作。

using (TestDbContext context = new TestDbContext())
        {
            foreach (Person person in People)
            {
                if (!(context.People.Any(p => p.ID == person.ID)))
                    context.People.Add(person);
                else
                {
                    context.People.Attach(person);
                    context.Entry<Person>(person).State = System.Data.EntityState.Modified;
                }
            }
            foreach (Car caar in Cars)
            {
                if (!(context.Cars.Any(c => c.ID == caar.ID)))
                    context.Cars.Add(caar);
                else
                {
                    context.Cars.Attach(caar);
                    context.Entry<Car>(caar).State = System.Data.EntityState.Modified;
                }
            }
            context.SaveChanges();
        }

如果我然后将汽车的所有者更改为第二人并再次运行代码,则车主属性不会更新。

Cars[0].Owner = People[1];

对我做错的任何想法?谢谢你的帮助。

2 个答案:

答案 0 :(得分:3)

我认为这是independent vs foreign key association的问题。您目前正在使用独立关联,并且car和person之间的关系实际上由具有其自身状态的单独条目对象管理(要访问此对象,您必须使用ObjectContext API)。将汽车的实体条目设置为修改状态不会更改关系条目的状态!简单的解决方案是使用外键关联,这意味着向您的汽车添加新的Guid PersonId属性并将其映射为Person导航属性的外键属性。

如果您坚持使用独立关联,则应仅在附加实体上更改关系,否则您将非常头痛地跟踪这些更改并将所有必需条目设置为正确状态。它应该足以创建对象,将它们附加到上下文中,并且只有在设置了汽车的所有者之后 - 希望它将被跟踪为更改。

答案 1 :(得分:1)

尝试这样的事情:

    using (TestDbContext context = new TestDbContext())
            {
                foreach (Person person in People)
                {
                    if (!(context.People.Any(p => p.ID == person.ID)))
                        context.People.Add(person);
                    else
                    {
                        context.People.Attach(person);
                        context.Entry<Person>(person).State = System.Data.EntityState.Modified;
                    }
                    context.SaveChanges();
                }
                foreach (Car caar in Cars)
                {
                    if (!(context.Cars.Any(c => c.ID == caar.ID)))
                        context.Cars.Add(caar);
                    else
                    {
                        context.Cars.Attach(caar);
                        context.Entry<Car>(caar).State = System.Data.EntityState.Modified;
                    }
                    context.SaveChanges();
                }

            }

我认为您的错误是由于context.SaveChanges展示位置(以及您的架构)。考虑通过Entity Framework为您的数据库上的每个操作使用专用方法(例如基本CRUD)。希望这会有所帮助。

编辑:使用CRUD approch:

public class PersonManager // CRUD
    {
        public void Create(Person person)
        {
            using (TestDbContext context = new TestDbContext())
            {
                context.Person.Add(person);
                context.SaveChanges();
            }
        }

        public void Update(Person person)
        {
            using (TestDbContext context = new TestDbContext())
            {
                context.Person.Attach(person);
                context.Entry(person).State = System.Data.EntityState.Modified;
                context.SaveChanges();
            }
        }
    }

您也可以创建此类static以适应您的体系结构。