Dispose DbContext not dispose the ObjectContext entities - asp.net

I'm using EF 5.0 to create a web and I have some issues disposing my context. All the times that I use a context is inside a using sentence, so the context should be disposed automatically but in a specific moment I get the next error when I try to attach an entity to a context:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
It semms that the entity is not disposed. How is the way to manage this situation? Do I have to dispose the ObjectContext to dispose the entities or is there any way to check if the Entity is attached?
Regards.

One way to do it is to detach the existing object before attaching. I don't have VS in front of me so I apologize if the code isn't exactly correct.
var existingObject = dbContext.Users.Local
.FirstOrDefault(x => x.id = newObject.id);
if (existingObject != null)
{
// remove object from local cache
dbContext.Entry(existingObject).State = EntityState.Detached;
}
dbContext.Users.Attach(newObject);
In case this doesn't fix the problem, you'll have to go to the old way of detaching objects.
// remove object from local cache
ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
objectContext.Detach(existingObject);

If you do something like that:
User u;
using (Entities ent = new Entities())
{
u = ent.Users.Single(a => a.ID == 123);
}
using (Entities ent2 = new Entities())
{
//loading the same user
User user2 = ent2.Users.Single(a => a.ID == 123);
//trying to attach the same object with the same key
ent2.Attach(u);
}
then you will get this error (I haven't tested this code).
EDIT: one of the solutions is to change the object's state:
ent2.Attach(u);
ent2.ObjectStateManager.ChangeObjectState(u, EntityState.Modified);
another solution is to check if the entity is already attached:
ObjectStateEntry state = null;
if(!ent2.ObjectStateManager.TryGetObjectStateEntry(((IEntityWithKey)u).EntityKey, out state))
{
ent2.Attach(u);
}

Dispose doesn't mean "reset to factory settings". It is a way to clean up unmanaged resources like database connections and such.

The problem has nothing to do with disposing a context or not. It even has nothing to do with having multiple contexts somewhere in place. If this would be the problem you would get the "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" exception which is totally different to your exception.
You can simulate your exception quite easily with only a single context:
using (var ctx = new MyContext())
{
var customer1 = new Customer { Id = 1 };
var customer2 = new Customer { Id = 1 }; // a second object with the same key
ctx.Customer.Attach(customer1);
ctx.Customer.Attach(customer2); // your exception will occur here
}
The problem causing this exception is normally more hidden, expecially if you keep in mind that attaching or setting a state (for example to Modified) will also attach all related entities in the object graph of the entity you are attaching. If in this graph are two objects with the same key you'll get the exception as well, although you didn't attach those related entities explicitly.
But it's impossible to find the exact reason without more details about your code.

Related

Linq-To-Sql SubmitChanges Not Updating Database

I've read multiple questions similar to this one but none are exactly my situation.
Using linq-to-sql I insert a new record and submit changes. Then, in the same web request, I pull that same record, and update it, then submit changes. The changes are not saved. The DatabaseContext is the same across both these operations.
Insert:
var transaction = _factory.CreateTransaction(siteId, userId, questionId, type, amount, transactionId, processor);
using (IUnitOfWork unitOfWork = UnitOfWork.Begin())
{
transaction.Amount = amount;
_transactionRepository.Add(transaction);
unitOfWork.Commit();
}
Select and Update:
ITransaction transaction = _transactionRepository.FindById(transactionId);
if (transaction == null) throw new Exception(Constants.ErrorCannotFindTransactionWithId.FormatWith(transactionId));
using (IUnitOfWork unitOfWork = UnitOfWork.Begin())
{
transaction.CrmId = crmId;
transaction.UpdatedAt = SystemTime.Now();
unitOfWork.Commit();
}
Here's the unit of work code:
public virtual void Commit()
{
if (_isDisposed)
{
throw new ObjectDisposedException(GetType().Name);
}
_database.SubmitChanges();
}
I even went into the designer.cs file and put a breakpoint on the field that is being set but not updated. I stepped through and it entered and execute the set code, so the Entity should be getting "notified" of the change to this field:
public string CrmId
{
get
{
return this._CrmId;
}
set
{
if ((this._CrmId != value))
{
this.OnCrmIdChanging(value);
this.SendPropertyChanging();
this._CrmId = value;
this.SendPropertyChanged("CrmId");
this.OnCrmIdChanged();
}
}
}
Other useful information:
ObjectTracking is enabled
No errors or exceptions when second SubmitChanges is called (just silently fails update)
SQL profiler shows insert and select but not the subsequent update statement. Linq-To-Sql is not generating the update statement.
There is only one database, one database string, so the update is not going to another database
The table has a primary key.
I don't know what would cause Linq-To-Sql to not issue the update command and not raise some kind of error. Perhaps the problem stems from using the same DataContext instance? I've even refreshed the object from the database using the DataContact.Refresh method before it is pulled for the update, but that didn't help.
I have found what is likely to be the root cause. I am using Unity. The initial insert is being performed in a service class with a PerWebRequest lifetime. The select and update is happening in a class with a Singleton lifetime. So my assumption that the DataContext instances are the same was incorrect.
So, in my class with the Singleton lifetime, I get a fresh instance of the database repository and perform the update and no problem.
Now I still don't know why the original code didn't work and my approach could still be considered more a workaround than a solution, but it did solve my problem and hopefully will be useful to others.

Multiplicity constraint violated. The role '...' of the relationship '...' has multiplicity 1 or 0..1

I'm getting the following error from my DbContext: "Multiplicity constraint violated. The role 'MyEntity' of the relationship 'MyModel.FK_ChildEntities_MyEntities' has multiplicity 1 or 0..1."
using ASP.NET, Entity Framework 4
Working with a detached entity
The error happens the second time I try to reattach an entity to the dbcontext. The scenario is an unsuccessful save followed by a reattempt.
I have a detached entity in session. The user changes properties in a form, add things, removes things and finally clicks save. I get an attached copy of the entity from a new instance of the dbcontext, apply changes from the detached entity to the attached entity, validate, find an error and abort. The user changes whatever and saves again.
On the second save, the whole save process repeats, only this time it all goes to hell. Pretty much everything is duplicated, causing one error or another or all of them. Values from views and lookup tables that are only supposed to be references are created new and reassigned id's. Most of those issues I've been able to resolve, but I'm left with the multiplicity error. Child elements are being created as exact copies of other child elements, down to the unique id, only in the Added state. Or, if I reference certain properties, instead of cloning an unmodified child, it drops the new one. Either way, none of the code is executing as it did the first time around.
I'm discarding the instance of the dbcontext and the attached entity each save attempt. I thought that would be enough to revert any changes but something must be sticking around. The only thing not discared or reset is the detached entity, which is in session, but I dont make any changes to it. At least not directly.
The code (very simplified) is something like this:
void Save()
{
using (var context = new MyContext())
{
// detached entity from session
MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];
// attached entity from context
MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);
// <remove children representing lookup table elements from detachedEntity to prevent duplicates>
// <remove children representing view elements from detachedEntity to prevent duplicates>
// <apply changes from detachedEntity to attachedEntity>
// <add new children>
// <remove deleted children>
// <update modified children>
// <set entity state to unchanged on view and lookup elements of attachedEntity to ensure no duplicates...>
// <validate>
if (errors.count>0)
// <report errors>
else
context.SaveChanges();
}
}
as an example, this generates a multiplicity error:
// represents first save:
using (var context = new MyContext())
{
// detached entity from session
MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];
// attached entity from context
MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);
int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug2 == 1;
}
// represents second save:
using (var context = new MyContext())
{
// detached entity from session
MyEntity detachedEntity = (MyEntity)Session["DetachedEntity"];
// attached entity from context
MyEntity attachedEntity = context.MyEntities.Single(x=>x.id == detachedEntity.id);
int debug1 = context.ChangeTracker.Entries<ChildEntity>().Count(); // debug1 == 0;
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
int debug2 = context.ChangeTracker.Entries<ChildEntity>().Count(); // multiplicity error;
}
somehow the dbcontext remembers what objects were added to it. if the exact same object shows up twice, it... blows
instead of adding child entities from my detached entity to the attached one, i should've been creating new copies of each child
ChildEntity detachedChild = detachedEntity.ChildEntities.First();
attachedEntity.ChildEntities.Add(new ChildEntity {
propertyA = detachedChild.propertyA,
propertyB = detachedChild.propertyB
});
instead of
attachedEntity.ChildEntities.Add(detachedEntity.ChildEntities.First());
The problem is that detachedChild.parent should be assigned attachedParent.
foreach(var detachedEntity in detachedEntities)
{
attachedEntity.ChildEntities.Add(detachedEntity);
detachedEntity.ParentEntity = attachedEntity;
}
What you are trying to do is something like:
ChildEntity childEntity = new ChildEntity()
{
//do mapping or provide data EXCEPt THE PRIMARY KEY
}
foreach(ParentEntity parentEntity in parentEntities)
{
parentEntity.Add(childEntity);
}
_dbContext.SaveChanges();
Result
Multiplicity constraint violated. The role '…' of the relationship '…' has multiplicity 1 or 0..1
The reason of the error message is
that everytime the _dbContext adds the childEntity to some parentEntity, it sets the generated primary key to the childEntity, so in the second loop of the foreach the primary key will be duplicated
The fix is - Method #1 - for simple scenarios
foreach(ParentEntity parentEntity in parentEntities)
{
//Make a new object every time
ChildEntity childEntity = new ChildEntity()
{
//do mapping or provide data EXCEPt THE PRIMARY KEY
}
parentEntity.Add(childEntity);
}
_dbContext.SaveChanges();
The fix is - Method #2 - for complex scenarios
using YOUR_PROJECT.ANY_FOLDER.DeepCopyExtensions;
ChildEntity childEntity = new ChildEntity()
{
//do mapping or provide data EXCEPt THE PRIMARY KEY
}
foreach(ParentEntity parentEntity in parentEntities)
{
//makes a copy of the childEntity object and pass it to the _dbContext, after saving each copy will be separated and the original object childEntity wont be touched
parentEntity.Add(DeepCopyByExpressionTrees.DeepCopyByExpressionTree(childEntity));
}
_dbContext.SaveChanges();
What is this method "DeepCopyByExpressionTrees.DeepCopyByExpressionTree(childEntity)" ?
Check this project here, download the source code, and only include the class file "DeepCopyByExpressionTrees.cs" to your project as a helper class and start using it any where.
Thanks
Make sure to inspect the properties of the object you are trying to add. In my case it was mistakenly referencing the same invalid object on each add which it didn't like and thus threw the same error you have here.
EF 6 Update
For me setting object state to added worked on sounds logical also
ChildEntity detachedChild = detachedEntity.ChildEntities.First();
var newChild = new ChildEntity {
propertyA = detachedChild.propertyA,
propertyB = detachedChild.propertyB
});
// Mark all added entity entity state to Added
attachedEntity.ChildEntities.Add(newChild );
db.Entry(newChild ).State = EntityState.Added;
http://www.entityframeworktutorial.net/EntityFramework4.3/update-one-to-many-entity-using-dbcontext.aspx
I experienced this error when I had navigation properties that had not been set or navigation properties that belonged to the wrong Code First DBContext
I fixed this by making the child collections in the parent entity virtual. This allows one to easily Update the entity when its child collections don't change, which, for me, was most of the time.
I had a similar issue, but mine arose from a AsNoTracking() after my query.
I had something like this
var myObject = dbContext.GetRepo<myType>().Query().AsNoTracking().SingleOrDefault()
And then later on I use that object to set anther object.
var myChild = new Child { parent = myObect }
and apparently EntityFramework tries to create a brand new object and hence causes a multiplicity error.

EF 5.0 Trouble updating entity which is already tracked

I'll preface this question with the following: I know there are a million posts on the internet about the old "An object with the same key already exists in the ObjectStateManager" issue. My scenario is a bit more complicated, I think.
I have a UnitOfWork class which creates a DbContext and passes it to any repository which is called. The pattern I'm using closely follows the Unit of Work tutorial on the ASP.NET site. Unlike the tutorial, my repositories take in Business entities, map them to data entities, and perform some CRUD action. My Business logic only works with Business entities. Here is what I'm trying to do in a sample Business Manager class:
_unitOfWork.Repository.Add(entity);
_unitOfWork.Save(); // context.SaveChanges() under the hood
...Perform some operations on the model...
_unitOfWork.Repository.Update(entity);
_unitOfWork.Save();
Here is a sample Update method from the repository:
public virtual void Update(entity)
{
var dataEntity = // map from business entity to data;
_context.Entry(dataEntity).State = EntityState.Modified;
}
It obviously fails on the last line. Here is where my confusion sets in:
The entity's State is Detached
When I attempt to change the State to Modified or Unchanged, it gives me the ObjectStateManager exception above.
When I attempt to detach the entity from the context (((IObjectContextAdapter)_context).ObjectContext.Detach(entity);) I get an exception about how the entity is not attached to the context, therefore, it cannot detach it. Very confusing (something fundamental I'm missing, for sure).
Many other posts suggest I make a database call, update that entity in the repository, then _unitOfWork.Save(). I don't like this approach. I shouldn't need to make an unnecessary network call to update an entity.
The Update method in the repository needs to handle two scenarios: 1) updating an entity which is not currently tracked by the context, and 2) updating an entity which IS currently tracked by the context. The second piece is what I'm struggling with.
Any help or insight is appreciated.
Thanks!
This means that there already is an object attached to the context with the same key as the new dataEntity. The existing object and the new entity both represent the same entry in the database but they are two different objects.
This may indicate that the lifespan of your _context is too long, but that's hard to judge from your code. It is certain though that the context was previously used to fetch an entity from the database that is subsequently duplicated by var dataEntity = ....
You may have to shorten the lifespan of the context, I can't tell. If you think it's OK you may want to use the Local collection to check whether the entity is already there. That will save the database round trip that Find may still make.
I found a hybrid solution which appears to work:
public virtual void Update(TB entity)
{
var dataEntity = Mapper.Map<TB, TD>(entity);
var pkey = _dbSet.Create().GetType().GetProperty("Id").GetValue(dataEntity);
var entry = _context.Entry(dataEntity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = _dbSet.Find(pkey);
if (attachedEntity != null)
{
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(dataEntity);
}
else
{
entry.State = EntityState.Modified;
}
}
else
{
entry.State = EntityState.Modified;
}
}

Updating object with related entities from detached state

When I query from the entity framework I always query in a detached state so that the records retrieved can be stored in cache for subsequent requests.
Right now I have a form that the user can edit which contains a parent record, and then two lists of parent records.
When the data is POSTed to the server, I take my view models and map them into the entity framework objects using AutoMapper. The data looks fine; AutoMapper is mapping the data correctly.
When I attach the object so that I can update it, an exception is thrown: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
//Exception happens here
orderContext.ShippingOrders.Attach(shippingOrder);
//Update the order itself; mark the order has being modified so the EF will update it.
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, System.Data.EntityState.Modified);
//Perform the update.
orderContext.SaveChanges();
}
}
The EntityFramework (EF) seems to think that my keys aren't lining up, but I'm not sure what isn't correct. The foreign key property does have the correct value, so I'm not sure what it's checking. Does anyone have any ideas?
You might try something like this:
ShippingOrder existingShippingOrder = orderContext.ShippingOrders.Find(shippingOrder.ID);
orderContext.Entry(existingShippingOrder ).CurrentValues.SetValues(shippingOrder);
Instead of
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, System.Data.EntityState.Modified);
try this
orderContext.Entry(ShippingOrder).State = EntityState.Modified;
as explained here
Insert or update pattern A common pattern for some applications is to
either Add an entity as new (resulting in a database insert) or Attach
an entity as existing and mark it as modified (resulting in a database
update) depending on the value of the primary key. For example, when
using database generated integer primary keys it is common to treat an
entity with a zero key as new and an entity with a non-zero key as
existing. This pattern can be achieved by setting the entity state
based on a check of the primary key value. For example:
public void InsertOrUpdate(DbContext context, Unicorn unicorn)
{
context.Entry(unicorn).State = unicorn.Id == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
you can try
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
orderContext.Entry(shippingOrder).State = shippingOrder.Id==0?
EntityState.Added :
EntityState.Modified;
orderContext.SaveChanges();
}
}
UPDATE:
for ObjectContext class you can try
public static void UpdateOrder(ShippingOrder shippingOrder) {
using (OrderEntity orderContext = new OrderEntity()) {
orderContext.ObjectStateManager.ChangeObjectState(shippingOrder, EntityState.Modified);
orderContext.SaveChanges();
}
}

Entity Framework NoTracking not working

I'm trying to run a no tracking query on my entities so that I can update them outside of the context. However, when the no tracking is not working and I get an exception stating
"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
This exception is thrown by a property which in terms of the database model is a foreign key to a separate table, do I need to somehow set notracking for this separate entity as well?
My code is:
List<EmailQueue> result = null;
using (Entities context = new Entities())
{
var emailQueueQuery = context.EmailQueues;
emailQueueQuery.MergeOption = System.Data.Objects.MergeOption.NoTracking;
result = emailQueueQuery.Execute(System.Data.Objects.MergeOption.NoTracking).ToList<EmailQueue>();
}
return result;
My wild guess is that you have lazy loading turned on?
If you dispose the ObjectContext, then lazy loading can't work.

Resources