Reputation: 151
I have trouble with adding an entity to database which contains an relation to existing object. I searched alot and couldn't find proper solution for this. I will describe this as simple as I can.
public class Store : IEntity
{
public int StoreId { get; set; }
public string StoreName { get; set; }
public virtual Address Address { get; set; }
public virtual Contractor Contractor { get; set; }
}
public class Product : IEntity
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public virtual Store Store { get; set; }
}
And in repository im adding records like this. This is generic class
public TEntity Add(TEntity entity)
{
using (var context = new TContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
Now when i try to add new record like this
var store = storeManager.GetBy(x => x.StoreId == 1);
var product = new Product() { ProductName = "Bananas", Store = store };
productManager.Add(product);
productManager.GetAll().ForEach(x => Console.WriteLine(x.ProductName + " " + x.Store.StoreId));
Store relation is added as new store and it get's new ID. Does someone have idea how i can solve this?
Example from database:
StoreId StoreName Address_AddressId Contractor_ContractorId
1 NULL 1 1
2 NULL 2 2
3 NULL 3 3
4 NULL 4 4
5 NULL 5 5
6 NULL 6 6
7 NULL 7 7
It's my first question on stackoverflow.
Upvotes: 0
Views: 873
Reputation: 48314
The most probable cause of your issue is that you are creating a new instance of your context for the insert opreration. Because of that, this new context not only gets a new product but also a store, which is received from another context, but this newly created context doesn't have any idea the store is already in the database.
A general issue then is incorrect managing the lifecycle of your database contexts. EF instances are tied to contexts that were used to receive them and you can't just put an entity from a context into another context.
Instead of creating a new context in each of your manager operations, you should share the instance of the database context between multiple managers.
public class StoreManager
{
public StoreManager( Context context )
{
this.context = context;
}
public TEntity Add(TEntity entity)
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
The orchestration has to first create the context and make sure it's shared between the two managers
var context = new DbContext();
var storeManager = new StoreManager( context );
var productManager = new ProductManager( context );
var store = storeManager.GetBy(x => x.StoreId == 1);
var product = new Product() { ProductName = "Bananas", Store = store };
productManager.Add(product);
productManager.GetAll().ForEach(x => Console.WriteLine(x.ProductName + " " +
x.Store.StoreId));
Usually, all these are created in a single scope, e.g. in a request scope, so that a single web request has a single database context and each repositories get the very same instance of the context.
You can also follow an official tutorial.
Upvotes: 1