The correct way to manage DbContext in EntityFramework6 (ii) "DbContext default Behavior"

Source: Internet
Author: User
Tags management studio sql server management sql server management studio

(Translator: One of the difficulties with using EF to develop applications is their DbContext lifecycle management, and whether your management strategy will support the need for upper-level services to use stand-alone transactions, nested transactions, parallel execution, asynchronous execution, etc.). Mehdi El Gueddari has done in-depth research and excellent work and has written an excellent article, and now I will share it with you in Chinese. Since the original text is too long, the translated article will be divided into four articles. This is the second article that you see. Original address: http://mehdi.me/ambient-dbcontext-in-ef6/) dbcontext default behavior

Generally, the default behavior of DbContext can be described as: "The right thing to do is by default."

Here are a few important actions you should remember in your mind about entityframework. This list describes the behavior of the EF access to SQL Server. There may be a slight difference in other databases. DbContext is not thread-safe

You should never access a DbContext derived class instance from multiple threads at the same time. This may cause multiple queries to be sent out at the same time through an identical database connection-it will destroy the state of the first-level cache maintained by DbContext-they are used to provide identity maps (identity map), change tracking, and function of work units.

In a multithreaded application, you must create a separate DbContext derived class instance for each thread.

The problem is, if DbContext is not thread-safe, how does IT support EF6 's asynchronous capabilities? It's simple: just make sure that only one asynchronous operation is executed at any given time (as the EF specification for asynchronous schemas describes). If you try to perform multiple operations concurrently on the same DbContext instance, such as through Dbset<t> Tolistasync () method executes multiple query statements concurrently, you will get a NotSupportedException with the following message.

A second operation started on the this context before a previous asynchronous operation. Use the ' await ' to ensure the any asynchronous operations have completed before calling the. Any instance members are not guaranteed to be thread safe.

the EF asynchronous function is to support the asynchronous programming model, not the concurrent programming model. modifications are persisted when and only if the SaveChanges () method is invoked

Any modifications to the entity, including updates, inserts, or deletions, are persisted to the database only when Dbcontext.savechanges () is invoked. If the DbContext instance is released before the SaveChanges () method is called, then these update operations, insert operations, and none of the delete operations can be persisted to the underlying database.

Here is the canonical way to implement a business transaction with EF:

  using (var context = new Mydbcontext (ConnectionString)) {/* * business logic is here.

                Add, modify, and delete data through the context.

                * * Throw any exception to roll back all changes.

                * * the SaveChanges () method cannot be invoked until the business transaction completes, which means that it cannot be saved in part or in the middle.

                * a SaveChanges () method can only be invoked once per business transaction. * If you find yourself needing to call the * SaveChanges () method multiple times within a business transaction, that means you implement multiple business activities within a service method * Works 

                This is definitely the "necessary medicine" for disaster. 

                * The client that invokes your service will naturally assume that your service method is committed or rolled back with atomic behavior-but your service may be submitting a partial submission, leaving the system in an inconsistent state.                                    

                * In this case, your service methods are--* into multiple service methods, and each service method just happens to achieve just one business transaction.

                */

                [...]

                Complete the business transaction and persist all changes. Context.

                SaveChanges ();

                Changes after this line of code cannot be rolled back. Context.

          SaveChanges () shall be any business transaction      The last line of code. }

NHibernate User considerations

If you have a nhibernate background, what you can tell you is that the EF will be able to persist changes to the database in the way that it is the most different from the nhibernate.

In NHibernate, the session operation is in autoflush mode by default. In this mode, the session will automatically persist all changes to the database before performing any ' select ' operations-ensuring that the entities that are persisted to the database are consistent with their memory status in the session. For NHibernate, the default behavior of EF is equivalent to setting Session.flushmode to never.

This behavior of the EF may cause some subtle bug--queries to accidentally return outdated or incorrect data. This is never possible by default NHibernate. But on the other hand, this has greatly simplified the problem of database transaction management.

One of the most intractable problems in NHibernate is the proper management of database transactions. Because NHibernate's session can automatically persist changes to the database at any point in its lifecycle, and can persist multiple times within a business transaction- There is not a well-defined point or method to open a database transaction to ensure that all modifications are committed or rolled back with atomic behavior.

The only reliable way to properly manage database transactions in NHibernate is to package all your service methods in an explicit database transaction. This is how most nhibernate-based applications are handled.

The downside of this approach is that it requires more time to open a database connection and transaction than is actually needed-hence increasing the competition for database locks and the likelihood of database deadlocks occurring. It is also easy for developers to inadvertently perform a lengthy computation or call to a remote service method without realizing that they are not even aware that they are in the context of a database transaction open.

The EF approach-only the SaveChanges () method must be packaged in an explicit database transaction (with an exception of a repeatable READ or serializable isolation level, of course), ensuring that database connections and transactions remain as short as possible. Use autocommit transactions (autocommit transaction) to perform read operations

DbContext does not support the opening of an explicit transaction to perform a read operation. It relies on SQL Server autocommit transactions (autocommit Transaction) (or implicit transactions (implicit Transaction), which are relatively not common operations if you enable them. Autocommit transactions (or implicit transactions) will use the default transaction isolation level that is configured by the database engine (read committed for SQL Server).

If you've been working for a while, especially if you've used NHibernate before, you've probably heard that autocommit transactions (or implicit transactions) are bad. In fact, write operations that rely on autocommit transactions can have a disastrous impact on performance .

However, the situation is very different for the read operation. You can run the following SQL script to see for yourself. For a SELECT statement, neither AUTOCOMMIT transaction nor implicit transaction has any noticeable performance impact.

* * * with autocommit transaction, implicit transaction, explicit transaction division executes 10000 * Times select query.

 * * These scripts assume that the database contains a list of users that has a column named ID * type int. * * If you are running in SQL Server Management Studio * Right-click the Query window, enter the query options-> Click the results and tick * "Give up the results after execution."  

Otherwise your test results will be affected by the grid's * Refresh validation/-----------------------------------------------------autocommit Transaction--6 sec DECLARE @i INT SET @i = 0 while @i < 100000 BEGIN SELECT IDs from dbo. The Users WHERE Id = @i SET @i = @i + 1 end----------------------------------------------------- 

        Implicit COMMIT Transaction--6 sec set implicit_transactions on DECLARE @i INT Set @i = 0 while @i < 100000 BEGIN SELECT Id from dbo.  

The Users WHERE Id = @i SET @i = @i + 1 end COMMIT; SET implicit_transactions off------------------------------------------------------Display Transaction--6 sec DECLARE @i INT SE T @i = 0 begin TRAN While @i < 100000 begin SELECT IDs from dbo.

      Users  WHERE Id = @i SET @i = @i + 1 End COMMIT TRAN   

Obviously, if you need to use a higher isolation level than the default read committed, then all read operations will be part of an explicit database transaction. In that case, you need to open your own business--ef will not do this for you. However, this typically only deals specifically with the specified business transaction. The EF default settings can be appropriate for most business transactions. use explicit transactions to perform write operations

EF automatically packs all operations into an explicit database transaction through the Dbcontext.savechanges () method-to ensure that all modifications applied to the context are either fully committed or completely rolled back.

The EF write operation uses the default transaction isolation level configured by the database engine (read committed for SQL Server).

NHibernate User considerations

This is another big difference between EF and nhibernate. In NHibernate, database transactions are fully in the hands of developers. NHibernate session will never automatically open an explicit database transaction. You can override the default behavior of the EF and control the database transaction scope and isolation level

using (var context = new Mydbcontext (ConnectionString))
   {
       using (var transaction =context. BeginTransaction (Isolationlevel.repeatableread))
       {
              [...]
              Context. SaveChanges ();
              Transaction.commit ();
        }
   

A very obvious side effect of manually controlling the scope of database transactions is that you have to keep the database connections and transactions open throughout the transaction scope.

You should try to keep the scope of the transaction as short as possible. Opening a database transaction for too long may have a significant impact on the performance and scalability of your application. Specifically, try not to invoke other service methods within the scope of a display transaction-they may perform long-running operations without realizing that they are invoked within an open database transaction. The EF does not have a built-in way to override the default isolation level used for autocommit transactions and automatic explicit transactions

As mentioned above, the EF relies on autocommit transactions to perform read operations and automatically opens an explicit transaction at the default isolation level of the database configuration when the SaveChanges () method is invoked.

Unfortunately there is no built-in way to rewrite these isolation levels, and if you want to use another isolation level, you have to open and manage database transactions yourself. automatically join a transactionscope of the surrounding environment via DbContext Open database connection

Alternatively, you can use TransactionScope to control the transaction scope and isolation level. The EF Open database connection automatically joins the TransactionScope of the surrounding environment.

Before EF6, using TransactionScope is the only reliable way to control the database transaction scope and isolation level.

In practice, try to avoid using TransactionScope unless you really need a distributed transaction. TransactionScope, commonly referred to as distributed transactions, is not necessary for most applications. And they usually bring more problems than the problems they solve. If you really need a distributed transaction, you can view the EF documentation section-using TransactionScope in the EF. DbContext instance should be released (but it may be fine if it is not released)

DbContext implements the IDisposable interface, so they should be released as soon as they are not needed.

In practice, however, the Dbcontext.dispose () method does not cause any problems unless you choose to explicitly control the database connection or transaction used by DbContext, as the Diego Vega, an EF team member explained.

This is good news-because you'll find that a lot of code doesn't release DbContext instances correctly. In particular, those who try to manage the DbContext instance lifecycle with a DI container-the reality is much trickier than it sounds.

A DI container, such as StructureMap, does not support releasing the components it creates. Therefore, if you rely on StructureMap to create DbContext instances, they will not be released-no matter what lifecycle mode you set for them. The only correct way to manage a release component with a DI container like this is to complicate your DI configuration and use a nested dependency injection container--as Jeremy Miller describes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.