简体   繁体   English

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

[英]Entity Framework - Updating relationship by changing foreign key

I have the two following models and DbContext: 我有以下两个模型和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; }
    }

I then declare a list of people and a list of cars, setting the owner of the first car to the first person in the list: 然后,我声明人员列表和汽车列表,将第一辆汽车的所有者设置为列表中的第一个人:

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") } };   

I save this off to the database using the following code and this works fine. 我使用以下代码将其保存到数据库中,并且工作正常。

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();
        }

If I then change the owner of the car to the second person and run the code again, the Car owner property doesn't get updated. 如果随后我将汽车的所有者更改为第二个人并再次运行代码,则“汽车所有者”属性不会得到更新。

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

Any ideas to what I'm doing wrong? 有什么想法我做错了吗? Thanks for any help. 谢谢你的帮助。

I believe this is a problem of independent vs foreign key association . 我相信这是独立与外键关联的问题 You are using independent association at the moment and the relation between car and person is actually managed by separate entry object which has its own state (to access this object you must use ObjectContext API). 您目前正在使用独立的关联,而汽车与人之间的关系实际上是由具有其自身状态的单独入口对象管理的(要访问此对象,您必须使用ObjectContext API)。 Setting the car's entity entry to modified state will not change the state of the entry for the relation! 将汽车的实体条目设置为修改状态不会更改该关系的条目状态! The simple solution is to use foreign key association instead which means adding new Guid PersonId property to your car and map it as foreign key property for Person navigation property. 简单的解决方案是使用外键关联,这意味着向您的汽车添加新的Guid PersonId属性,并将其映射为Person导航属性的外键属性。

If you insist on using independent associations you should change relations only on attached entities otherwise you will had a strong headache with tracking those changes and setting all required entries with correct state. 如果您坚持使用独立的关联,则只能更改关联实体上的关联,否则跟踪这些更改并将所有必需的条目设置为正确的状态将非常麻烦。 It should be enough to create objects, attach them to context and only after that set the owner of the car - hopefully it will be tracked as a change. 创建对象并将它们附加到上下文中就足够了,并且只有在这之后设置汽车的所有者-希望它将作为更改进行跟踪。

Try something like this : 尝试这样的事情:

    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();
                }

            }

I think your error is due to the context.SaveChanges placements (and partialy your architecture). 我认为您的错误是由于context.SaveChanges位置(以及部分架构)引起的。 Consider using a dedicated method (a basic CRUD for instance) for each operation on your DB via Entity Framework. 考虑通过实体框架对数据库上的每个操作使用专用方法(例如,基本的CRUD)。 Hope this helps. 希望这可以帮助。

Edit : With a CRUD approch : 编辑:使用CRUD方法:

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();
            }
        }
    }

You could also make this class static in order to fit to your architecture. 您也可以使此类static ,以适应您的体系结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM