简体   繁体   中英

How to save an entity with a child entity which already exists in EF core?

I ran into a very weird problem I've never seen before. I'm using .net CORE 3.0 + EF. I have two database models, which are

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Dog Dog { get; set; }
}

and

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

So, let's say I already have a Dog record in my database with id=1 and Name = "Bimbo". Now, I want to add a person with an existing dog :

var p = new Person
{
    Name = "Peter",
    Dog = new Dog
    {
        Id = 1
    };
};

_dbContext.Persons.Add(p);

Then I get

Cannot insert explicit value for identity column in table 'Dogs' when IDENTITY_INSERT is set to OFF

I understand that EF tries to insert a dog as a new record, while I need it to bind my new Person record with an existing Dog record.

I found this solution which suggests setting a foreign key explicitly. Is there another way to do it? Or is it the right way to handle such situation? EF Core insert explicit value for identity column

you can explicitly add the Foreign key to person

   public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int DogId {get;set;}
        public Dog Dog { get; set; }
    }

then you can the add the dog as reference without load it to context

var p = new Person
{
    Name = "Peter",
    DogId = 1
};

_dbContext.Persons.Add(p)

;

You have three options to do that

  1. Use the Foreign-Key property

    using ( var db = new MyDbContext(options) ) { var person = new Person { Name = "Paul", DogId = 1 }; db.Persons.Add(person); await db.SaveChangesAsync(); }
  2. Load the dog instance from the context and use that instance

    using ( var db = new MyDbContext(options) ) { var dog = db.Dogs.Find(1); var person = new Person { Name = "Paul", Dog = dog }; db.Persons.Add(person); await db.SaveChangesAsync(); }
  3. Create a dog instance with explicit ID and attach that to the context

    using ( var db = new MyDbContext(options) ) { var dog = new Dog { Id = 1 }; db.Attach(dog); var person = new Person { Name = "Paul", Dog = dog }; db.Persons.Add(person); await db.SaveChangesAsync(); }

See working example on .net fiddle

When you add the Person object to the context, EF sets its state to Added, as well as any object it references that has their primary key set (as stated here ). This is why EF tries to insert a new Dog object into the database with a new id, while the exception states that the ids for the Dogs table are generated by the database.

To work around this you can manually set the state of the new Dog object to Unchanged which will prevent EF from inserting a new record to the database.:

_dbContext.Entry(person.Dog).State = EntityState.Unchanged

Better solutions will be to add a DogId property to the Person object and set it instead of creating a new Dog instance or to load the Dog object from the database and set it to the Dog property of the Person object (as suggested in the comments).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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