如何使用ADO.NET实现工作单元(UoW)模式并在ASP.NET MVC

时间:2016-10-19 16:43:03

标签: c# dependency-injection asp.net-mvc-5 ado.net ninject

我之前已经问过这个问题,但是在那些问题中没有足够详细的实际实现,所以我决定搜索一些关于如何实现这个问题的信息,这就是我&#39到目前为止:

IUnitOfWork界面

public interface IUnitOfWork : IDisposable
{
    IDomainTableRepository DomainTables { get; }        
    IVariableRepository Variables { get; }
    IModelRepository Models { get; }     
    IStructureRepository Structures { get; }
    ISentenceRepository Sentences { get; }
    IExpressionRepository Expressions { get; }
    IReturnRepository Returns { get; }

    void Commit();
}

IUnitOfWork的实施:

public class SqlUnitOfWork : IUnitOfWork
    {
        const string ConnectionStringName = "DefaultConnection";    
        private AdoNetContext _context;
        private DomainTableRepository _domainTables;
        private VariableRepository _variables;   
        private ModelRepository _models;      
        private StructureRepository _structures; 
        private SentenceRepository _sentences;
        private ExpressionRepository _expressions;            
        private ReturnRepository _returns; 

        public SqlUnitOfWork()
        {
            var connectionString =
                 ConfigurationManager
                 .ConnectionStrings[ConnectionStringName]
                 .ConnectionString;

            _context = new AdoNetContext(connectionString, true); 
        }       
        public IDomainTableRepository DomainTables
        {
            get
            {
                if (_domainTables == null)
                {
                    _domainTables = new DomainTableRepository(_context);
                }
                return _domainTables;
            }
        }      

        //...getters for the remaining repositories    

        public void Commit()
        {
            _context.SaveChanges();
        }

        #region IDisposable Support
        private bool disposedValue = false; 

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    _context.Dispose();
                } 
                disposedValue = true;
            }
        } 
        public void Dispose()
        {            
            Dispose(true);            
        }
        #endregion


    }

AdoNetContext类

本课程实施的所有功劳归于@jgauffin。

His original blog post can be found here.

public class AdoNetContext : IDisposable
    {
        private IDbConnection _connection;
        private bool _ownsConnection;
        private IDbTransaction _transaction;

        public AdoNetContext(string connectionString, bool ownsConnection)
        {
            _connection = new SqlConnection(connectionString);
            _connection.Open();
            _ownsConnection = ownsConnection;
            _transaction = _connection.BeginTransaction();
        }    
        public IDbCommand CreateCommand()
        {                
            var command = _connection.CreateCommand();
            command.Transaction = _transaction;
            return command;
        }    
        public void SaveChanges()
        {
            if (_transaction == null)
            {
                throw new InvalidOperationException("Transaction have already been already been commited. Check your transaction handling.");
            }
            _transaction.Commit();
            _transaction = null;
        }    
        public void Dispose()
        {
            if (_transaction != null)
            {
                _transaction.Rollback();
                _transaction = null;
            }    
            if (_connection != null && _ownsConnection)
            {
                _connection.Close();
                _connection = null;
            }
        }
    }

使用AdoNetContext的存储库(DomainTableRepository)的实现:

public class DomainTableRepository : IDomainTableRepository
    {
        private AdoNetContext _context;    
        public DomainTableRepository(AdoNetContext context)
        {
            _context = context;
        }    
        public DomainTable Get(int id)
        {
            DomainTable table;
            using (var commandTable = _context.CreateCommand())
            {
                commandTable.CommandType = CommandType.StoredProcedure;
                commandTable.CommandText = "up_DomainTable_GetById";

                commandTable.Parameters.Add(commandTable.CreateParameter("@pId", id));

                table = ToList(commandTable).FirstOrDefault();
            }
            return table;
        }    
        public IEnumerable<DomainTable> GetAll(int pageIndex = 1, int pageSize = 10)
        {    
            using (var command = _context.CreateCommand())
            {
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "up_DomainTable_GetAll";
                command.Parameters.Add(command.CreateParameter("@pPageIndex", pageIndex));
                command.Parameters.Add(command.CreateParameter("@pPageSize", pageSize));    
                return ToList(command).ToList();
            } 
        }    
        public int Remove(DomainTable entity)
        {
            using (var command = _context.CreateCommand())
            {
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "up_DomainTable_Delete";
                command.Parameters.Add(command.CreateParameter("@pId", entity.Id));
                    return command.ExecuteNonQuery();
            }
        }       
    }

我为张贴这么多代码而道歉,但我想确保你理解我想要问的一切。

首先,我为UoW(IUnitOfWork)创建了一个界面,因为将来我可能想要改成像EF这样的ORM,但是因为我只是迈出了我的第一步 - 结束编程我想从ADO.NET和存储过程开始。

以下是关于使用ADO.NET实现UoW模式及其在ASP.NET MVC中的用法的问题:

1)鉴于 AdoNetContext (管理数据库连接和事务的代码)的代码,总是创建一个事务是否有任何性能损失?

这是我在SQL书中读到的:&#34;执行SELECT 事务中的语句可以在引用的表上创建锁定,这可以阻止其他用户或会话执行工作或读取数据&#34; 在C#中创建的事务是否与SQL中的对应事务完全相同?

2)正如您在IUnitOfWork及其实现(UnitOfWork)中所看到的,我在应用程序中拥有每个存储库的只读属性。这是一个常见的&#34;模式&#34;我已经在很多关于EF的教程中看到过,我发现它非常方便,因为每次我创建一个IUnitOfWork实例时,我都可以访问它的所有存储库,而且我不必将我的代码弄乱我的代码。我需要在特定Action(来自Controller)中实例化我需要的存储库。

您是否认为每次创建/注入新的IUnitOfWork实例时,实例化所有存储库(如SQLUnitOfWork所做的那样)会花费太多开销?在某些情况下我可能会使用它同时有4个或5个存储库,但在大多数情况下,我只会在同一个action中使用1个或2个。

3)我想使用DI(可能是Ninject)将IUnitOfWork的实例注入到我的Controller中。这种方式稍后当我使用另一个持久性框架时,我只需要更改此行kernel.Bind<IUnitOfWork>().To<SqlUnitOfWork>();来自SqlUnitOfWork,让我们说EFUnitOfWork

我在这里遇到的问题是,DisposeSqlUnitOfWork中的AdoNetContext方法从未被调用过,而且我想要使用DI I&#39; d而是将SqlUnitOfWork的实例化包装在每个using的{​​{1}}语句中,而不是泄漏内存,以便我可以使用DI。

所以这就是我想问你们的人。

我在尝试学习之前请先点击关闭链接或将问题标记为重复,请花些时间阅读我的问题。

感谢。

0 个答案:

没有答案