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?
Related
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.
I am uploading a lot of data to a database using entity framework. I have a lot of different entities with relations between them.
My problem is that sometimes the object I'm uploading might already be in the database, but when I look up that object and find it, I can't add it to my locally made entities, because they belong to different contexts.
For example, I have the entities Sailor and Booze, which have a relation. I have a new sailor Ackbar and I know his favourite booze is rum and I want to persist this to the database.
I make a new sailor and set its name to Ackbar. Then I look up to see if Booze has an entry called rum. If it has, I try to add it to Ackbar. When I do this, EF complains that the new sailor and the booze from the database belong to different contexts.
If I try to attach sailor to the context, it complains that sailor has a null entity key.
How can I build all these relations without saving anything to the database before I'm done editing the relationships?
I suggest that you alter your code to use the same Context for reading and writing. Having multiple contexts for a single transaction is not a better option than having a Context that's alive for a few minutes.
I have an existing application with a SQL database that has been coded using a database first model (I create an EDMX file every time I have schema changes).
Some additional development (windows services which support the original application) has been done which uses EF POCO/DbContext as the data layer instead of an EF EDMX file. No initializer settings were ever configured in the DbContexts, but they never modified the database as the DbSet objects always matched the tables.
Now, I've written a seperate application that uses the existing database but only its own, new tables, which it creates itself using EFs initializer. I had thought this would be a great time to use EF Code First to handle managing these new tables. Everything worked fine the first time I ran the application, but now I am getting this error from some of my original EF POCO DbContexts (which never used an initializer).
The model backing the 'ServerContext' context has changed since the
database was created. Consider using Code First Migrations to update
the database
After some investigation, I've discovered that EF compares a hash of its schema with some stored hash in the sql server somewhere. This value doesn't exist until a context has actually used an initializer on the database (in my case, not until the most recent application added its tables).
Now, my other DbContexts throw an error as they read the now existing hash value and it doesn't match its own. The EF connection using the EDMX doesn't have any errors.
It seems that the solution would be to put this line in protected override void OnModelCreating(DbModelBuilder modelBuilder) in all the DbContexts experiencing the issue
Database.SetInitializer<NameOfThisContext>(null);
But what if later on I wanted to write another application and have it create its own tables again using EF Code first, now I will never be able to reconcile the hash between this theoretical even newer context and the one that is causing the issue right now.
Is there a way to clear the hash that EF stores in the database? Is EF smart enough to only alter tables that exist as a DbSet in the current context? Any insights appreciated.
Yes, Bounded DB contexts is actually good practice.
eg a base context class, to use common connection to DB, each sub class, uses the
Database.SetInitializer(null); as you suggest.
Then go ahead and have 1 large context that has the "view of the DB" and this context is responsible for all migrations and ONLY that context shoudl do that. A single source of truth.
Having multiple contexts responsible for the DB migration is a nightmare I dont think you will solve.
Messing with the system entries created by code first migrations can only end in tears.
Exactly the topic you describe I saw in A julie Lerman video.
Her suggested solution was a single "Migration" context and then use many Bounded DB contexts.
In case you have a pluralsight account:
http://pluralsight.com/training/players/PsodPlayer?author=julie-lerman&name=efarchitecture-m2-boundedcontext&mode=live&clip=11&course=efarchitecture
What EF version are you using? EF Code First used to store hash of the SSDL in the EdmMetadata table. Then in .NET Framework 4.3 thingh changed a little bit and the EdmMetadata table was replaced by __MigrationsHistory table (see this blog post for more details). But it appears to me that what you are really looking after is multi-tenant migrations where you can have multiple context using the same database. This feature has been introduced in EF6 - (currently Aplpha2 version is publicly available) Also, note that EdmMetadata/__MigrationHistory tables are specific to CodeFirst. If you are using the designer (Model First/Database First) no additional information is stored in the database and the EF model is not checked whether it matches the database. This can lead to hard to debug bugs and/or data corruption.
I'm using a single instance of DbContext scenario to shadow entire copy of the database locally in a WPF app. I've heard this is bad practice, but my database is small and I need an entire copy of it locally while the app is running.
An extension method for IQueryable, Load() lets me preload the elements of a DbSet<>, so that I can bind things to the Local property of DbSet<>. Data in the database changes rapidly, so I want to SaveChanges() and reload everything, even objects that are already tracked. Calling the Load() method again doesn't update the items that are tracked but are not marked as changed, which are already loaded.
What is the preferred method of reloading the preloaded items in a DbSet<>? Off the top of my head, I can only think of calling SaveChanges(), then go through all entries and set both tracked and original values to the current values in the database, then Load() whatever new objects that might have been added. In my scenario it's not possible to delete objects, but I might have to support item deletion in the long run. This doesn't seem right, there should be a way to drop everything and reload. It would seem that it's easier to drop my context and just start anew, but all the elements in WPF are already bound to the Local´ObservableCollection<>, and this just messes up the interface.
This is not the way you are supposed to use DbContext, and because of that it is almost impossible to reload the data. Keeping a single context around for a long time is incorrect usage. The link will also answer why your tracked entities are not updated.
You can selectively reload a single entity by calling Reload on DbEntityEntry:
context.Entry(entity).Reload();
You can also revert back to ObjectContext and use ObjectQuery with MergeOption.OverrideChanges, or use Refresh for a collection of entities with RefreshMode.StoreWins.
All these approaches suffers some problems:
If the record is deleted in the database, it will not be removed from the context.
Changes in relations are not always refreshed.
The only correct way to get fresh data is Dispose the context, create a new one and load everything from scratch - and you are doing this anyway.
With Entity Framework 4.1, the recommendation for WPF data binding has changed to use .Local and a persistent DbContext.
http://blogs.msdn.com/b/efdesign/archive/2010/09/08/data-binding-with-dbcontext.aspx
It's, of course, possible to dispose of it whenever you need to, but it can negatively impact the UI if you do.
Here's another method, but I'm not sure that it takes EF4.1's features into account:
http://msdn.microsoft.com/en-us/library/cc716735.aspx
DbContexts are supposed to live short time,
Consider after saving changes disposing it and reloading all from the start.
Have 2 sets of objects.. one from db and another for binding.
Please use using() for CRUD.It will automatically reload the updated data.
using (myDbContext context = new myDbContext())
{
}
Best Regards,
Thet Tin Oo
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..