Mark Micallef
Mark Micallef

Reputation: 2788

Entity Framework trying to insert parent object

The Problem

I'm using Entity Framework to add a complex object model to the database. I'm encountering an issue where I try to insert a child object that EF is also trying to insert the parent object, which is causing an integrity issue in the database.

Explanation

For my example, let's assume we have two tables:

  1. Shop
  2. ShopPerformance

A Shop can have many ShopPerformance entries, the ShopPerformance must have a Shop, and the Shop record already exists in the database (so EF should be leaving it alone and focusing on the ShopPerformance).

In my example, I am attempting to add the ShopPerformance only (in this case the instance of ShopPerformance is called "performance":

this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();

When I call SaveChanges(), EF is trying to insert the Shop as well, which causes a constraint error in the database as it has constraints to prevent duplicate entries (based on the shop's name).

Things I've Tried

I've tried setting the Shop property in ShopPerformance to null to stop EF from doing things I don't want to do (it still has the ShopID as a separate property). First I tried:

Shop theShop = performance.Shop;
performance.Shop = null;
this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();
performance.Shop = theShop;

In this scenario, EF somehow re-establishes the link between shop and performance and tries to insert shop again.

Then I tried:

Shop theShop = performance.Shop;
this.db.Entry(performance).Entity.Shop = null;
this.db.Entry(performance).State = System.Data.EntityState.Added;
this.db.SaveChanges();
this.db.Entry(performance).Entity.Shop = theShop;

This causes null reference exceptions.

Desired Resolution

I'm looking for a way to insert my performance object without EF fiddling around with the Shop. This is completely breaking my work right now.

TL;DR

I want Entity Framework to Insert/Update ONLY the object I have told it to and none of the related objects. How can I do this?

Upvotes: 2

Views: 1764

Answers (2)

Yuliam Chandra
Yuliam Chandra

Reputation: 14640

You are working with disconnected object, both performance and performance.Shop are entities that are not tracked by EF, and EF has no idea what is the status of performance.Shop.

When adding new performance with existing performance.Shop, EF doesn't know that performance.Shop is an existing entity, and EF will mark all un-tracked objects in the graph as Added too.

The reason it happens is that when you use the DbSet.Add method (that is, Screencasts.Add), not only is the state of the root entity marked “Added,” but everything in the graph that the context was not previously aware of is marked Added as well. - MSDN

What you need to do is.

  • If you have the foreign key association, you could just assign the id instead of the reference.

    performance.ShopId = performance.Shop.Id;
    performance.Shop = null;
    this.db.Entry(performance).State = System.Data.EntityState.Added;
    this.db.SaveChanges();
    
  • Or you need to let EF knows that performance.Shop is an existing entity by attaching (status = Unchanged) it first to the context.

    this.db.Entry(performance.Shop).State = EntityState.Unchanged;
    this.db.Entry(performance).State = EntityState.Added;
    this.db.SaveChanges();
    

Upvotes: 5

Pavel Krymets
Pavel Krymets

Reputation: 6293

Did you tried:

var shop = this.db.shops.Find(id);
shop.Performances.Add(new Performance());

this.db.SaveChanges();

Or

this.db.performances.Add(new Performance() { ShopId = id });
this.db.SaveChanges();

Upvotes: 1

Related Questions