Concurrency exception:element at index 0 in colection of objects to refresh has a nul EntityKey property value or is not atached to ObjectStateManager - entity-framework

I am getting above concurrency exception when data is saved concurrently. User is prompted with concurrency error window stating do he wish to keep local PC (his) changes or keep database changes. According to his choice on click of these 2 buttons, 2 commands corresponding to below methods are written.
public void RefreshClientWins(IEnumerable entities)
{
var objectContext = ((IObjectContextAdapter)Context).ObjectContext;
objectContext.Refresh(RefreshMode.ClientWins, entities);
}
public void RefreshStoreWins(IEnumerable entities)
{
var objectContext = ((IObjectContextAdapter)Context).ObjectContext;
objectContext.Refresh(RefreshMode.StoreWins, entities);
}

Related

Entity Framework Update DbContext

I have a Repository project like this.
https://github.com/tugberkugurlu/GenericRepository/tree/master/src
I have a method.
public void Edit(TEntity entity)
{
_dbContext.SetAsModified(entity);
}
public void SetAsAdded<TEntity>(TEntity entity) where TEntity : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Added;
}
But I am getting while update record. I am getting sometimes this error.
Attaching an entity of type 'TP.Model' failed because
another entity of the same type already has the same primary key
value. This can happen when using the 'Attach' method or setting the
state of an entity to 'Unchanged' or 'Modified' if any entities in the
graph have conflicting key values. This may be because some entities
are new and have not yet received database-generated key values. In
this case use the 'Add' method or the 'Added' entity state to track
the graph and then set the state of non-new entities to 'Unchanged' or
'Modified' as appropriate.
I solved the problem like this. I checked the first columns. Afterwards, I did something like this.
_dbSet = dbContext.DbSet<TEntity>();
The rest is cake.
_dbSet.Attach(entity);
DbEntityEntry entry = _dbContext.Entry(entity);
foreach (var proprty in entry.OriginalValues.PropertyNames)
{
var Current = entry.CurrentValues.GetValue<object>(proprty);
var New = entry.GetDatabaseValues().GetValue<object>(proprty);
if (Current != null)
{
if (!object.Equals(New, Current))
{
entry.Property(proprty).IsModified = true;
}
}
}

Duplicate queries while removing multiple rows in one transaction in Entity Framework 6

I'm working with EF 6 and have the repository class such this:
public class EfRepository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
public EfRepository(DbContext context)
{
_context = context;
}
....
public void Delete(IEnumerable<T> entities)
{
// skip checks
using (var transaction = _context.Database.BeginTransaction())
{
try
{
_context.Set<T>().RemoveRange(entities);
_context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
}
In my controller I have repository instance IRepository<Connection> _repository than binded with Autofac to EfRepository class.
Then I remove multiple items (and everything works fine!):
IEnumerable<Connection> connections = // get some connections;
_repository.Delete(connections); // everything fine - records was removed
But when I open my site with installed MiniProfiler it shows me duplicate sql-query warning:
My question is why I use transactions but still has duplicate sql warning?
Thank you.
This is because Entity Framework currently sends one query per item to be deleted. It does not batch them all into one query. So MiniProfiler is correctly reporting on what is happening - duplicate delete queries (with exception of the param value) are being submitted.
What is your transaction.Commit() doing? Maybe you can add the code of this method to your question.
I am also deleting entites from my database but more like this:
public virtual void Delete(TEntity entityToDelete)
{
if (Context.Entry(entityToDelete).State == EntityState.Detached)
{
DBSet.Attach(entityToDelete);
}
DBSet.Remove(entityToDelete);
}
I think there are no differences between Remove and RemoveRange, but maybe you should check the state first?

Attaching Entity to context fails because it already exist

I use the Unity of Work and Generic Repository of CodeCamper.
to update an entity, the generic repo has:
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
the web api method:
public HttpResponseMessage Put(MyEditModel editModel)
{
var model = editModel.MapToMyEntity();
_myManager.Update(model);
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
The Update method:
public void Update(MyEntity model)
{
Uow.MyEntities.Update(model);
Uow.Commit();
}
In the Unityof Work:
IRepository<MyEntity> MyEntities { get; }
When updating an entity I get the following error:
Additional information: Attaching an entity of type 'X' failed because another entity of the same type already has the same primary key value.
This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values.
This may be because some entities are new and have not yet received database-generated key values.
In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
The update works fine, when it is the first method you call of the repository.
(I created an entity with an id already in the DB and called the Update.)
The update doesn't work when you do a get of the entity before you update it.
(For example, I get an entity X, convert it to a DTO, then change some values in the UI,
then call a web api that creates an entity X with the new values and
call the Update of the repository.)
Any ideas to avoid this?
When you have a CRUD app, you always call the get before the update.
I'm using my own attach method:
public void Attach<E>(ref E entity)
{
if (entity == null)
{
return;
}
try
{
ObjectStateEntry entry;
bool attach = false;
if (ObjectStateManager.TryGetObjectStateEntry(CreateEntityKey(entitySetName, entity), out entry))
{
attach = entry.State == EntityState.Detached;
E existingEntityInCache = (E)entry.Entity;
if (!existingEntityInCache.Equals(entity))
{
existingEntityInCache.SetAllPropertiesFromEntity(entity);
}
entity = existingEntityInCache;
}
else
{
attach = true;
}
if (attach)
objectContext.AttachTo(entitySetName, entity);
}
catch (Exception ex)
{
throw new Exception("...");
}
}
I had the same issue. The problem was in mixed contexts. When you read entity from DB in context1. Then if you can update this entity with contex2 (other instance of the same context with own entity cache). This may throw an exception.
Pls check for references too:
by context1:
read entity1 with referenced entity2 from DB
by context2:
read entity2 from DB. Then update entity1 (with referenced entity2 from context1).
When you try attach entity1 with referenced entity2 to context2, this throw exception because entity2 already exists in context2.
The solution is use only one context for this operation.

Generic repository to update an entire aggregate

I am using the repository pattern to provide access to and saving of my aggregates.
The problem is the updating of aggregates which consist of a relationship of entities.
For example, take the Order and OrderItem relationship. The aggregate root is Order which manages its own OrderItem collection. An OrderRepository would thus be responsible for updating the whole aggregate (there would be no OrderItemRepository).
Data persistence is handled using Entity Framework 6.
Update repository method (DbContext.SaveChanges() occurs elsewhere):
public void Update(TDataEntity item)
{
var entry = context.Entry<TDataEntity>(item);
if (entry.State == EntityState.Detached)
{
var set = context.Set<TDataEntity>();
TDataEntity attachedEntity = set.Local.SingleOrDefault(e => e.Id.Equals(item.Id));
if (attachedEntity != null)
{
// If the identity is already attached, rather set the state values
var attachedEntry = context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(item);
}
else
{
entry.State = EntityState.Modified;
}
}
}
In my above example, only the Order entity will be updated, not its associated OrderItem collection.
Would I have to attach all the OrderItem entities? How could I do this generically?
Julie Lerman gives a nice way to deal with how to update an entire aggregate in her book Programming Entity Framework: DbContext.
As she writes:
When a disconnected entity graph arrives on the server side, the
server will not know the state of the entities. You need to provide a
way for the state to be discovered so that the context can be made
aware of each entity’s state.
This technique is called painting the state.
There are mainly two ways to do that:
Iterate through the graph using your knowledge of the model and set the state for each entity
Build a generic approach to track state
The second option is really nice and consists in creating an interface that every entity in your model will implement. Julie uses an IObjectWithState interface that tells the current state of the entity:
public interface IObjectWithState
{
State State { get; set; }
}
public enum State
{
Added,
Unchanged,
Modified,
Deleted
}
First thing you have to do is to automatically set the state to Unchanged for every entity retrieved from the DB, by adding a constructor in your Context class that hooks up an event:
public YourContext()
{
((IObjectContextAdapter)this).ObjectContext
.ObjectMaterialized += (sender, args) =>
{
var entity = args.Entity as IObjectWithState;
if (entity != null)
{
entity.State = State.Unchanged;
}
};
}
Then change your Order and OrderItem classes to implement the IObjectWithState interface and call this ApplyChanges method accepting the root entity as parameter:
private static void ApplyChanges<TEntity>(TEntity root)
where TEntity : class, IObjectWithState
{
using (var context = new YourContext())
{
context.Set<TEntity>().Add(root);
CheckForEntitiesWithoutStateInterface(context);
foreach (var entry in context.ChangeTracker
.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.State);
}
context.SaveChanges();
}
}
private static void CheckForEntitiesWithoutStateInterface(YourContext context)
{
var entitiesWithoutState =
from e in context.ChangeTracker.Entries()
where !(e.Entity is IObjectWithState)
select e;
if (entitiesWithoutState.Any())
{
throw new NotSupportedException("All entities must implement IObjectWithState");
}
}
Last but not least, do not forget to set the right state of your graph entities before calling ApplyChanges ;-) (You could even mix Modified and Deleted states within the same graph.)
Julie proposes to go even further in her book:
you may find yourself wanting to be more granular with the way
modified properties are tracked. Rather than marking the entire entity
as modified, you might want only the properties that have actually
changed to be marked as modified.
In addition to marking an entity as modified, the client is also
responsible for recording which properties have been modified. One way
to do this would be to add a list of modified property names to the
state tracking interface.
But as my answer is already too long, go read her book if you want to know more ;-)
My opinionated (DDD specific) answer would be:
Cut off the EF entities at the data layer.
Ensure your data layer only returns domain entities (not EF entities).
Forget about the lazy-loading and IQueryable() goodness (read: nightmare) of EF.
Consider using a document database.
Don't use generic repositories.
The only way I've found to do what you ask in EF is to first delete or deactivate all order items in the database that are a child of the order, then add or reactivate all order items in the database that are now part of your newly updated order.
So you have done well on update method for your aggregate root, look at this domain model:
public class ProductCategory : EntityBase<Guid>
{
public virtual string Name { get; set; }
}
public class Product : EntityBase<Guid>, IAggregateRoot
{
private readonly IList<ProductCategory> _productCategories = new List<ProductCategory>();
public void AddProductCategory(ProductCategory productCategory)
{
_productCategories.Add(productCategory);
}
}
it was just a product which has a product category, I've just created the ProductRepository as my aggregateroot is product(not product category) but I want to add the product category when I create or update the product in service layer:
public CreateProductResponse CreateProduct(CreateProductRequest request)
{
var response = new CreateProductResponse();
try
{
var productModel = request.ProductViewModel.ConvertToProductModel();
Product product=new Product();
product.AddProductCategory(productModel.ProductCategory);
_productRepository.Add(productModel);
_unitOfWork.Commit();
}
catch (Exception exception)
{
response.Success = false;
}
return response;
}
I just wanted to show you how to create domain methods for entities in domain and use it in service or application layer. as you can see the code below adds the ProductCategory category via productRepository in database:
product.AddProductCategory(productModel.ProductCategory);
now for updating the same entity you can ask for ProductRepository and fetch the entity and make changes on it.
note that for retrieving entity and value object of and aggregate separately you can write query service or readOnlyRepository:
public class BlogTagReadOnlyRepository : ReadOnlyRepository<BlogTag, string>, IBlogTagReadOnlyRepository
{
public IEnumerable<BlogTag> GetAllBlogTagsQuery(string tagName)
{
throw new NotImplementedException();
}
}
hope it helps

How to Prevent EF5 LocalDB Connection From Closing

I've built an applciation using EF5 and CodeFirst. At runtime my application creates a LocalDB databse file and a class-level instance of a DataContext. Everything works fine however inserts are slow after about 50,000 records (approx 20MB MDF file). In debug I can see the internal Connection's state is set to 'Closed'. I assume EF5 is closing the connection after each insert and then re-opening it when needed.
How can I prevent Entity Framework from closing the connection? This is a local that will potentially need to import up to 500k records in the shortest period of time.
Looking at the State of the Connection shows frequent changes. The string to the left is a date stamp in yyyyMMddHHmmssfff format...
20130818072134139 : Original: Open / Current: Closed
20130818072134160 : Original: Closed / Current: Open
20130818072134163 : Original: Open / Current: Closed
20130818072134185 : Original: Closed / Current: Open
20130818072134188 : Original: Open / Current: Closed
20130818072134209 : Original: Closed / Current: Open
20130818072134212 : Original: Open / Current: Closed
20130818072134246 : Original: Closed / Current: Open
These are just a small snippet from the same ONE SECOND. This must be [at least] part of the slow inserts.
Your problem has nothing to do with opening and closing connections. You appear to have jumped to the wrong conclusion, and are racing to solve the wrong problem. In fact, LocalDb has no connections, since it's a local file based database.
Your problem is that you have a class level data context. Entity Framework data contexts are designed to be short lived. They have no real resource management, and they assume that once a transaction is done you will dispose and destroy it.
Your problem, of getting slow after a period of time is common when you do not destroy the data context after every transaction, as the context keeps growing larger and larger, and allocating and re-allocating memory. As the context gets larger, EF must walk the list of records in the local cache each time SaveChanges is called, and as more and more records are inserted, this takes longer and longer.
I suggest you rethink your design on this. You have several options, the first of which is to simply do as I suggested and destroy the context after every transaction. The second, is to bypass the model completely if you are simply doing inserts and use a straight sql command using context.Database.ExecuteSqlCommand() or even better, use Sql Bulk inserts instead.
More than likely you are keeping the objects around and bloating the Context. You may be able to prove this by using Task Manager and watching the memory usage. It will probably be growing in size.
If you do not need the objects any longer then DETACH them from the context as soon as you are through. You could use a Repository to do this quite easily.
First, the code to detach them...
GenericRepository<Path> repo = new GenericRepository<Path>(context);
repo.Detach(item);
Next, the generic repository...
public class GenericRepository<T> : IRepository<T>
where T : class
{
protected DbSet<T> DbSet { get; set; }
protected DbContext Context { get; set; }
public GenericRepository(DbContext context)
{
if (context == null)
{
throw new ArgumentException("An instance of DbContext is " +
"required to use this repository.", "context");
}
this.Context = context;
this.DbSet = this.Context.Set<T>();
}
public IQueryable<T> GetAll()
{
return this.DbSet;
}
public T GetById(int id)
{
return this.DbSet.Find(id);
}
public void Add(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State != EntityState.Detached)
{
entry.State = EntityState.Added;
}
else
{
this.DbSet.Add(entity);
}
}
public void Update(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State == EntityState.Detached)
{
this.DbSet.Attach(entity);
}
entry.State = EntityState.Modified;
}
public void Delete(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State != EntityState.Deleted)
{
entry.State = EntityState.Deleted;
}
else
{
this.DbSet.Attach(entity);
this.DbSet.Remove(entity);
}
}
public void Delete(int id)
{
var entity = this.GetById(id);
if (entity != null)
{
this.Delete(entity);
}
}
public void Detach(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
entry.State = EntityState.Detached;
}
}
I hope this helps.