Assuming I am never writing with EF, will never call SaveChanges for example, Is EF safe for concurrent reads from the same ObjectContext?
It may still be initialising a database connection and reading new objects, or updating existing objects (or deleting!) but it won't be writing anything to the db, so no transactions (I assume).
Thanks
ObjectContext and related EF classes are not thread safe so don't use them for concurrent operations. If you need to run concurrent data access use a new context for every thread.
Related
I've read that in Entity Framework Core HiLo pattern "Hi" part is managed by database and "Lo" part is managed by Entity Framework in memory.
How does Entity Framework generate "Lo" part without round-trip to database?
How persist the "Lo" value between requests?
And most important, is this pattern thread safety?
Thanks!
The HiLo generator works by occasionally reserving a block of IDs on the server then using IDs from that block on the client as needed. You only need to hit the database when reserving the block, so if your block size is 100, you'll round-trip every 100 IDs.
Yes, it's safe to have multiple contexts assigning IDs concurrently since the block is atomically assigned by the database server. Each DbContext instance will have its own block.
I have been using MigrateDatabaseToLatestVersion as the database initializer in order to use Seed method with migrations.
In order to learn more about DBinitializers in EF I had a look at this blog post. I don't know this post is still relevant for EF6 or not, but gives a good overview I think.
After making a research on thread-safety and possible race conditions for database initialization, I have some questions about the thread-safety and consistency of database initialization and seeding.
1) First of all database initialization is thread safe or not? I am using MigrateDatabaseToLatestVersion and creating multiple threads in the same AppDomain (each thread creates a new DbContext). When I start the application first of these threads should initialize the database (and also seed it for the first time in an AppDomain I think). In that case any race condition is possible between the different threads in the same AppDomain? Initialization is said to be thread safe in a single AppDomain?
2) Also, is it a good practice to call SaveChanges() in the Seed method more than one time. For ex: I have a normalized database which contains many tables connected with other by foreign keys. If I seed each table one by one and calling SaveChanges() on each of them in the same table, is it possible to cause any trouble. For ex. is it possible for another IDbInitializer in another AppDomain to populate these tables at the same time?
3) As far as I understood MigrateDatabaseToLatestVersion runs the Seed method once per each AppDomain. So, it means even in the same application, each new AppDomain instance will try to Seed the same database which may be a performance bottleneck I think. Is there any way to prevent this?
It seems a lot has changed in EF (code first) since many of the questions on SO were written... many refer to EF4 and I am using EF6, I know stored procedures are a new feature in EF6 for instance.
My application periodically calls an Xml web service and simply dumps the objects in a database; I have a C# object for each Xml type which maps directly to one DB table using EF.
Objects may be created or updated depending if they are already in the DB. My application has no interest in the content of the objects and should not keep them in memory as it may be running for weeks at a time.
What is an efficient way to Create-or-Update objects in this scenario? I am imagining that my DbContext will be created (and disposed) each time the web service is polled, so it will never already know what objects are in the DB. In a non-EF world I'd probably create a stored-procedure CreateOrUpdate(...) so I wonder if there is a simple parallel.
I do not need to use stored procedures with EF but it sounds like it might be a nicer idea. And since we're not used to EF and not all our modules are using it, haveing the stored-procedures in the DB in case someone else wants to use them seems useful.
I'm using EF (EF Core, actually, with ASP.NET Core on OSX, but I believe this is more of a general "newbie-style" EF question, so please read on...)
I built a little logging routine that uses EF to publish log entries to my database. Sort of like this, called from a repository class:
WebLog log = new WebLog(source, path, message);
Context.WebLogs.Add(log);
Context.SaveChanges();
Where WebLog is a simple model class, Context.WebLogs is a DbSet<WebLog> collection, and Context is obviously the DbContext. I believe this is quite straightforward.
But my question is this: if I continue to add new log entries to the Context.WebLogs collection and I never do anything like reboot my server, isn't the collection just going to grow without bounds? Is there some kind of "purge" or "flush" action I can take periodically to manage memory usage (without affecting the committed rows in the database, of course--I want those to persist). Or is DbSet some sort of a special collection that won't do this?
As mentioned by DevilSuichiro above, the recommended approach is to limit the lifetime of the instances of DbContext. E.g. in a Web application you typically use a DbContext instance per request, so an unbounded number of entities added doesn't become a problem.
The closest thing to a "flush" operation is SaveChanges() that method will not try to remove references to tracked entities, as DbContext is designed to be reused after SaveChanges().
In previous versions of EF we had a Detach() API that you could use to get rid of an individual tracked reference but we don't have that API in DbContext or anywhere in EF Core.
BTW, having an instance of DbContext that is shared between multiple requests is extremely problematic because DbContext is not thread safe.
I am working on a very large application with over 100 modules, and almost 500 tables in the database. We are converting this application to WPF/WCF using Entity Framework 4.2 Code First. Our database is SQL Anywhere 11. Because of the size of the database, we are using an approach similar to Bounded DbContexts, as described here http://msdn.microsoft.com/en-us/magazine/jj883952.aspx by Julie Lerman.
Each of our modules creates its own DbContext, modeling only the subset of the database that it needs.
However, we have run into a serious problem with the way DbContexts are created. Our modules are not neatly self-contained, nor can they be. Some contain operations that are called from several other modules. And when they are, they need to participate in transactions started by the calling modules. (And for architectural reasons, DTC is not an option for us.) In our old ADO architecture, there was no problem passing an open connection from module to module in order to support transactions.
I've looked at various DbContext constructor overloads, and tried managing the transaction from EntityConnection vs. the StoreConnection, and as far as I can tell, there is no combination that allows ModuleA to begin a transaction, call a function in ModuleB, and have ModuleB's DbContext participate in the transaction.
It comes down to two simple things:
Case 1. If I construct DbContextB with DbContextA's EntityConnection, DbContextB is not built with its own model metadata; it reuses DbContextA's metadata. Since the Contexts have different collections of DbSets, all ModuleB's queries fail. (The entity type is not a part of the current context.)
Case 2. If I construct DbContextB with ModuleA's StoreConnection, DbContextB does not recognize the StoreConnection's open transaction at the EntityConnection level, so EF tries to start a new transaction when ModuleB calls SaveChanges(). Since the database connection in fact has an open transaction, this generates a database exception. (Connection does not support parallel transactions.)
Is there any way to 1) force DbContextB to build its own model in Case 1, or 2) get DbContextB's ObjectContext to respect its StoreConnection's transaction state in Case 2?
(By the way, I saw some encouraging things in the EF6 alpha, but after testing it out, found the only difference was that I could create DbContextB on an open connection. But even then, the above 2 problems still exist.)
I suggest you try use the TransactionScope object to manage this task for you. As long as all of your DbContexts use the same connection string (not connection object) the transaction should not try to enlist MS-DTC.