ASP.NET MVC 4+EFシリーズの7つの倉庫の中の事務の現実的なIUnitOfWorkインタフェース

17778 ワード

EFをよく知っている人はたくさんいます.EF自体のSaveChange()メソッドは,トランザクション機能を持つことである.SaveChange()メソッドの前のDbConextに対する操作は、トランザクションとして扱われます.1つのフレームワークシステムでは、SaveChangeは需要を満たすことができないかもしれません.そのため、IUnitOfWorkの存在に必要な条件を提供しました.IUnitOfWorkはインタフェースにすぎず、仕様を提供しています.具体的な実装についてはORMごとに異なる.当時はこの基準に従ってやれば私たちは支持していました.:).
/*****************************************************
 *   :egojit
 *   :2012-7-13
 *   :    
 * ***************************************************/
namespace EgojitFramework.Domain
{
    /// <summary>
    ////// </summary>
    public interface IUnitOfWork
    {
        /// <summary>
        ///  
        ///     Bool              
        /// </summary>
        bool Committed { get; }
        /// <summary>
        ///       
        /// </summary>
        void Commit();
        /// <summary>
        ///       
        /// </summary>
        void Rollback();
    }
}

この言い訳は簡単で、トランザクションがコミットされたかどうかを判定するための属性です.もう2つの方法は、名前の通り、1つはトランザクションをコミットし、1つはトランザクションをロールバックします.
次に言うまでもなく、私たちは彼の継承クラスと事務がどのように実現されているかに注目します.私が提供したソースコードを開くと、RepositoryContextManagerクラスに継承されています.
 #region IUnitOfWork   
        /// <summary>
        ///          
        /// </summary>
        public bool Committed
        {
            get { return context.Committed; }
        }
        /// <summary>
        ///    
        /// </summary>
        public void Commit()
        {
            context.Commit();
        }
        /// <summary>
        ///     
        /// </summary>
        public void Rollback()
        {
            context.Rollback();
        }

        #endregion

このコードからは何も見えませんが、焦らないでください.これは私が皆さんと実現過程を分析しただけです.上のcontextは実はIrepositoryContextタイプです.このインタフェースを開くと、IUnitOfWorkも継承されていることがわかりやすくなります.IrepositoryContextの実装クラスでは、すべての実装が理解されます.RepositoryContextクラスはIrepositorryContextインタフェースを継承し、コードからIUnitOfWorkインタフェースに関するメソッドのヨーロッパ式抽象abstractを発見し、それは必ず実現される.このRepositoryContext倉庫環境は、特殊なORMに対して実現されるのではなく、一般的なものであることは理解に難くない.ここで私たちのORMツールがEFであることを簡単に考えます.では、その実現はE n t i t y F r a m workRepositoryContextクラスにあるに違いありません.そう、私たちの推測は間違いありません.EntityFrameworkRepositoryContext:
public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext

彼がRepositoryContextというクラスを継承しているのを見て、私たちはこのクラスに戻ります.
using System;
using System.Collections.Generic;
using EgojitFramework.Infrastructure;
/*****************************************************
 *   :egojit
 *   :2012-7-13
 *   :        
 * ***************************************************/
namespace EgojitFramework.Domain.Repositories
{
    /// <summary>
    ///        
    /// </summary>
    public abstract class RepositoryContext : DisposableObject, IRepositoryContext
    {
        #region     
        private readonly Guid id = Guid.NewGuid();
        [ThreadStatic]
        private readonly Dictionary<Guid, object> newCollection = new Dictionary<Guid, object>();
        [ThreadStatic]
        private readonly Dictionary<Guid, object> modifiedCollection = new Dictionary<Guid, object>();
        [ThreadStatic]
        private readonly Dictionary<Guid, object> deletedCollection = new Dictionary<Guid, object>();
        [ThreadStatic]
        private bool committed = true;
        #endregion

また、削除、修正、追加のオブジェクトを配置し、GUIDをKeyとして使用するコードも発見されました.これがローカルメモリで、まずオブジェクトの変更をこの3つのセットに配置します.見てもいい
RepositoryContext   IRepositoryContext                 
        /// <summary>
        ///              
        /// </summary>
        /// <typeparam name="TAggregateRoot">     .</typeparam>
        /// <param name="obj">         .</param>
        public virtual void RegisterNew<TAggregateRoot>(TAggregateRoot obj) where TAggregateRoot : class, IAggregateRoot
        {
            if (obj.ID.Equals(Guid.Empty))
                throw new ArgumentException("The ID of the object is empty.", "obj");
            if (modifiedCollection.ContainsKey(obj.ID))
                throw new InvalidOperationException("The object cannot be registered as a new object since it was marked as modified.");
            if (newCollection.ContainsKey(obj.ID))
                throw new InvalidOperationException("The object has already been registered as a new object.");
            newCollection.Add(obj.ID, obj);
            committed = false;
        }

このようにして辞書に入れます.そしてcommitted=false;EntityFrameworkRepositoryContextクラスに戻り、トランザクションの実装コードを見てみましょう.
/*****************************************************
 *   :egojit
 *   :2012-8-14
 *   :    
 * ***************************************************/
using System;
using System.Data.Entity;
using System.Data.Entity.Validation;
using EgojitFramework.Domain.Model;

namespace EgojitFramework.Domain.Repositories
{
    public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
    {
        private readonly EgojitFrameworkContext ctx = new EgojitFrameworkContext();
        private readonly object sync = new object();

        public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
        {
            ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Deleted;
            Committed = false;
        }

        public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
        {
            ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified;
            Committed = false;
        }

        public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
        {
            ctx.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Added;
            Committed = false;
        }

        public override void Commit()
        {
            if (!Committed)
            {
                lock (sync)
                {
                    try
                    {
                        ctx.SaveChanges();
                        Committed = true;
                    }
                    catch (DbEntityValidationException e)
                    {
                        foreach (var eve in e.EntityValidationErrors)
                        {
                            Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                                eve.Entry.Entity.GetType().Name, eve.Entry.State);
                            foreach (var ve in eve.ValidationErrors)
                            {
                                Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                                    ve.PropertyName, ve.ErrorMessage);
                            }
                        }
                        throw;
                    }
                }
            }
        }

        public override void Rollback()
        {
            Committed = false;
        }

これで、トランザクション全体の実装プロセスがわかりました.このように実現した事務はもっと柔軟ではないか.頻繁にデータベースにリンクする必要はありません.すべての操作はローカルメモリにあります.私たちが提出するまで.
本文はブログ園とegojitの所有に属して、転載して出典を明記してください