In Entity Framework it's easy enough to get an existing item without tracking:
context.Widgets.AsNoTracking().Single(x=>x.Id == id);
What if I want to add a new item without tracking it once it's added? As soon as you do this:
context.Widgets.Add(newWidget);
the instance is tracked. Even if I detach the instance from the context, once it's attached again the context still keeps track of OriginalValues and introduces the usual issues with concurrent updates etc.
Is there a way to:
add a new entity
and/or:
attach an existing detached entity
to a DbContext while enforcing the equivalent AsNoTracking behaviour?
Try this:
context.Widgets.Add(newWidget);
context.SaveChanges();
context.Entry(newWidget).State = EntityState.Detached;
Edit:
The DbContext class, with its stateful nature, was made to track data changes.
This approach made EntityFramework not suited to be used with types that are designed to be transient, like seem to be the "Widget" instance.
The code above should be doing the job: reuse a data structure to be used in a 'semi-persistent' context, but should be optimized with batching.
The reason I commented 'Use Dapper' is that I've been very frustrated in the past by EF, which creates a lot more problems than it solves. Using a stateless Orm is a lot more efficient.
Related
Is it possible to do Add, AddAsync, Update etc in .NET Core without the entity being tracked afterwards without having to write code to specifically detach the context from tracking the entity?
// select, its possible to do no trackiing
var audit = _dbContext.Audit.First().AsNoTracking();
// doing an add or update, audit is now tracked unless it's detached
_dbContext.Audit.Add(audit);
int rows = _dbContext.SaveChanges();
_dbContext.Entry(audit).State = EntityState.Detached;
I ask this because I have a windows service that consumes RabbitMq messages and writes to the database. RabbitMq receives messages via an event handler. So the database essentially becomes a singleton even though its added as transient. I could create a new db context each time. but it seems overkill. Or is there a better way?
You shouldn't have singleton DbContext because it is not thread safe.
You can take a look at this blog post for different approaches of managing DbContext:
https://mehdi.me/ambient-dbcontext-in-ef6/
We are switching from ObjectContext to DbContext in your EF6 desktop application. At the moment I struggle with reloading data from the DB without recreating the whole context. Unfortunately we work partly with a long living context approach which I can't change easily.
To reload the properties of an entity (without the navigation properties) with the newest values from the database (store wins), we use CreateObjectSet() with MergeOption.OverwriteChanges from the ObjectContext. I am now trying to replace it with a DbContext alternative.
I have found the following options:
DbContext.Entry(entity).Reload()
Overwrite the values of each property in the entity using the values from DbContext.Entry(entity).GetDatabaseValues()
Detaching the entity and fetch it again e.g. using Find()
Even when disabling AutoDetectChanges all these options are still much slower as when using CreateObjectSet(). By the way: Creating a new context and fetch the values again would be slower too but not that much.
Am I missing something or does DbContext not have a performant alternative (apart from creating a new context) for CreateObjectSet() with StoreWins?
Is it possible (this is an EF6 DbContext using CodeFirst) to detect any entities that have been passed to a given data context for saving but are actually attached to a different context?
Entity framework just gives a generic, cannot save because entities are attached to another context error, but doesn't give any information about which entity is attached to a different context. This makes this situation particularly hard to debug.
I know about changeTracker.Entries() (of which I'm not sure these records actually appear in), and I know I can compare the entities of this against the local context to see if they are tracked, but neither of these options seem to allow me to determine whether the entity is being tracked by a different context.
You cannot do that, because the entity does not store any pointer to the context, it's actually the other way around (the context knows the entity).
What you can do, if you are using lazy loading in your entities, is, using reflection, find out the context from which the entity came from. But I wouldn't advise it.
I'm implemented the unit of work like this tutorial explained:
http://www.codeproject.com/Articles/543810/Dependency-Injection-and-Unit-Of-Work-using-Castle
Though now I encounter a strange problem.
I load within a unit of work (in the transaction) an entity from the database
I update a property of that entity
I call not the save method on my repository
The transaction is committed
In this scenario, I would expect that the updated property is not persisted to the database. But it is. So an entity loaded in my session is tracked and committed to the database without calling save. What is causing this? And is there a way to tell Nhibernate not to update those entities if the save is not called?
I realize I can work around this to update only a property when I need to update. The only risk is by accident updating the property by mistake and it is then very hard to find this problem. (and for example someone new, not knowing this could easily make a mistake)
The explanation requires understanding the difference between a transient and a persistent entity. A transient entity is a new entity and it is made persistent by calling Save(). An entity that has been retrieved using NHibernate is already persistent and any changes made to it will be automatically saved when the session is flushed. NHibernate's goal is to make the database consistent with the domain model when the session ends.
See chapter 9 in the documentation.
I was wondering if it was wise to cache the Entity Framework's ObjectContext object in the Cache; will this give me issues with multiple connections at the same time that the user will experience issues with that?
I've gotten errors like: 'connection is currently closed' and wondered if that was due to multiple users and caching the ObjectContext, or if it was related to say hitting refresh multiple times or stopping the page and quickly doing something else (something that we did do to get the error).
I agree with above. However, I do cache the object context in HttpContext.Current.Items collection without any issues. Also a good read:
http://dotnetslackers.com/articles/ado_net/managing-entity-framework-objectcontext-lifespan-and-scope-in-n-layered-asp-net-applications.aspx
I wouldn't advise it. The ObjectContext needs to be active to observe changes to any entities you are actively working with or you'd need to disconnect any active entities prior to caching the ObjectContext.
If you have no active entities, then there's no real need to cache an ObjectContext. In EFv1 working with disconnected entities was problematic at best, so I'd either not cache or wait for the Entity Framework v4 which allows for more manageable entities (self tracking entities, POCO entities etc).
Just thought I'd add one last point - multiple threads - could be problematic as well. Applying Changes will attempt to commit all changes tracked by the ObjectContext. If multiple users are sharing a single Context... well, hopefully you can see the problems..