30
2016
08

.Net框架搭建之2、SQL Server MEF依赖注入 MVC Repository框架_part3

UnitOfWorkContextBase.cs

/* ==============================================================================
 * 功能描述:UnitOfWorkContextBase  
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 10:59:20
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Validation;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Component
{
    /// <summary>
    ///     单元操作实现基类
    /// </summary>
    public abstract class UnitOfWorkContextBase : IUnitOfWorkContext
    {
        /// <summary>
        /// 获取 当前使用的数据访问上下文对象
        /// </summary>
        protected abstract DbContext Context { get; }
        /// <summary>
        ///     获取 当前单元操作是否已被提交
        /// </summary>
        public bool IsCommitted { get; private set; }
        public DbContext DbContext { get { return Context; } }
        /// <summary>
        ///     提交当前单元操作的结果
        /// </summary>
        /// <param name="validateOnSaveEnabled">保存时是否自动验证跟踪实体</param>
        /// <returns></returns>
        public int Commit(bool validateOnSaveEnabled = false)
        {
            //validateOnSaveEnabled=true时莫名其妙报错,暂时去掉
            validateOnSaveEnabled = false;
            if (IsCommitted)
            {
                return 0;
            }
            try
            {
                int result = Context.SaveChanges(validateOnSaveEnabled);
                IsCommitted = true;
                return result;
            }
            catch (DbEntityValidationException ex)
            {
                var entry = ex.EntityValidationErrors.First().Entry;
                var err = ex.EntityValidationErrors.First().ValidationErrors.First();
                var msg = err.ErrorMessage;
                try
                {
                    var displayName = entry.Entity.GetType().GetProperty(err.PropertyName).GetPropertyDisplayName();
                    msg = string.Format(msg, displayName, entry.CurrentValues.GetValue<object>(err.PropertyName));
                }
                catch (Exception)
                {
                }
                throw new Exception(msg);
            }
            catch (DbUpdateException e)
            {
                if (e.InnerException != null && e.InnerException.InnerException is SqlException)
                {
                    var sqlEx = e.InnerException.InnerException as SqlException;
                    //string msg = DataHelper.GetSqlExceptionMessage(sqlEx.Number);
                    throw sqlEx; //PublicHelper.ThrowDataAccessException("提交数据更新时发生异常:" + msg, sqlEx);
                }
                throw;
            }
        }
        /// <summary>
        ///  把当前单元操作标记成未提交状态,发生错误时,不能回滚事务,不要调用!
        /// </summary>
        public void Rollback()
        {
            IsCommitted = false;
        }
        public void Dispose()
        {
            //if (!IsCommitted)
            //{
            //    Commit();
            //}
            //if (Context != null)
            //    Context.Dispose();
        }
        /// <summary>
        ///   为指定的类型返回 System.Data.Entity.DbSet,这将允许对上下文中的给定实体执行 CRUD 操作。
        /// </summary>
        /// <typeparam name="TEntity"> 应为其返回一个集的实体类型。 </typeparam>
        /// <returns> 给定实体类型的 System.Data.Entity.DbSet 实例。 </returns>
        public DbSet<TEntity> Set<TEntity>() where TEntity : class// EntityBase<TKey>
        {
            return Context.Set<TEntity>();
        }
        /// <summary>
        ///     注册一个新的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterNew<TEntity>(TEntity entity) where TEntity : class// EntityBase<TKey>
        {
            EntityState state = Context.Entry(entity).State;
            if (state == EntityState.Detached)
            {
                Context.Entry(entity).State = EntityState.Added;
            }
            IsCommitted = false;
        }
        /// <summary>
        ///     批量注册多个新的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        public void RegisterNew<TEntity>(IEnumerable<TEntity> entities) where TEntity : class// EntityBase<TKey>
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach (TEntity entity in entities)
                {
                    RegisterNew<TEntity>(entity);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }
        public void RegisterModified<TEntity>(IEnumerable<TEntity> entities) where TEntity : class// EntityBase<TKey>
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach (TEntity entity in entities)
                {
                    EntityState state = Context.Entry(entity).State;
                    if (state == EntityState.Detached)
                    {
                        Context.Entry(entity).State = EntityState.Modified;
                    }
                    IsCommitted = false;
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }
        /// <summary>
        ///     注册一个更改的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterModified<TEntity>(TEntity entity) where TEntity : class// EntityBase<TKey>
        {
            Context.Update<TEntity>(entity);
            IsCommitted = false;
        }
        /// <summary>
        /// 使用指定的属性表达式指定注册更改的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity">要注册的类型</typeparam>
        /// <param name="propertyExpression">属性表达式,包含要更新的实体属性</param>
        /// <param name="entity">附带新值的实体信息,必须包含主键</param>
        public void RegisterModified<TEntity>(Expression<Func<TEntity, object>> propertyExpression, TEntity entity) where TEntity : class// EntityBase<TKey>
        {
            //Context.Update<TEntity>(propertyExpression, entity);
            //IsCommitted = false;
        }
        /// <summary>
        ///   注册一个删除的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterDeleted<TEntity>(TEntity entity) where TEntity : class// EntityBase<TKey>
        {
            Context.Entry(entity).State = EntityState.Deleted;
            IsCommitted = false;
        }
        /// <summary>
        ///   批量注册多个删除的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        public void RegisterDeleted<TEntity>(IEnumerable<TEntity> entities) where TEntity : class// EntityBase<TKey>
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach (TEntity entity in entities)
                {
                    RegisterDeleted<TEntity>(entity);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }
        /// <summary>
        ///   从仓储上下文中删除注册的对象
        /// </summary>
        /// <typeparam name="TEntity"> 要删除注册的类型 </typeparam>
        /// <param name="entity"> 要删除的对象 </param>
        public void RegisterRemove<TEntity>(TEntity entity) where TEntity : class// EntityBase<TKey>
        {
            Context.Set<TEntity>().Remove(entity);
            IsCommitted = false;
        }
        /// <summary>
        /// EF SQL 语句返回 dataTable
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public DataSet SqlQueryForDataSet(CommandType commandType, string sql, SqlParameter[] parameters)
        {
            using (var conn = new SqlConnection { ConnectionString = Context.Database.Connection.ConnectionString })
            {
                if (conn.State != ConnectionState.Open)
                {
                    conn.Open();
                }
                var cmd = new SqlCommand { Connection = conn, CommandText = sql, CommandType = commandType, CommandTimeout = conn.ConnectionTimeout };
                if (parameters != null && parameters.Length > 0)
                {
                    foreach (var item in parameters)
                    {
                        cmd.Parameters.Add(item);
                    }
                }
                var adapter = new SqlDataAdapter(cmd);
                var ds = new DataSet();
                adapter.Fill(ds);
                cmd.Parameters.Clear();
                return ds;
            }
        }
    }
}


至此,Component层也完成了,里面一些其他公共方法 ,我就不一一写出了,到时候我会在文章最后附上源码。

3、Core 数据访问层处理

有了Component层之后,Core层对于开发人员来说就变得十分简单了,但是要创建几个简单的类去满足Component层的需要的映射对象。 

SysUserConfiguration.cs

using InjectExample.Component;
using InjectExample.Model;
/* ==============================================================================
 * 功能描述:SysUserConfiguration  
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 14:33:08
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Composition;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.Configurations
{
    /// <summary>
    /// 实体类-数据表映射 此代码应由模版自动生成
    /// EfDbContext 会把实现 IEntityMapper 接口的实体类自动添加到数据库实体上下文,如果没有查询数据库时会报表
    /// </summary>    
    [Export(typeof(IEntityMapper))]
    public partial class SysUserConfiguration : EntityTypeConfiguration<SysUser>, IEntityMapper
    {
        /// <summary>
        /// 实体类-数据表映射构造函数
        /// </summary>
        public SysUserConfiguration()
        {
            SysUserConfigurationAppend();
        }
        /// <summary>
        /// 额外的数据映射
        /// </summary>
        partial void SysUserConfigurationAppend();
        /// <summary>
        /// 将当前实体映射对象注册到当前数据访问上下文实体映射配置注册器中
        /// </summary>
        /// <param name="configurations">实体映射配置注册器</param>
        public void RegistTo(ConfigurationRegistrar configurations)
        {
            configurations.Add(this);
        }
    }
}

SysUserInfoConfiguration.cs

using InjectExample.Component;
using InjectExample.Model;
/* ==============================================================================
 * 功能描述:SysUserConfiguration  
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 14:33:08
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Composition;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity.ModelConfiguration.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.Configurations
{
    /// <summary>
    /// 实体类-数据表映射 此代码应由模版自动生成
    /// EfDbContext 会把实现 IEntityMapper 接口的实体类自动添加到数据库实体上下文,如果没有查询数据库时会报表
    /// </summary>    
    [Export(typeof(IEntityMapper))]
    public partial class SysUserInfoConfiguration : EntityTypeConfiguration<SysUserInfo>, IEntityMapper
    {
        /// <summary>
        /// 实体类-数据表映射构造函数
        /// </summary>
        public SysUserInfoConfiguration()
        {
            SysUserInfoConfigurationAppend();
        }
        /// <summary>
        /// 额外的数据映射
        /// </summary>
        partial void SysUserInfoConfigurationAppend();
        /// <summary>
        /// 将当前实体映射对象注册到当前数据访问上下文实体映射配置注册器中
        /// </summary>
        /// <param name="configurations">实体映射配置注册器</param>
        public void RegistTo(ConfigurationRegistrar configurations)
        {
            configurations.Add(this);
        }
    }
}

ISysUserRepository.cs

using InjectExample.Component;
using InjectExample.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.Repositories
{
    /// <summary>
    ///   仓储操作层接口 此代码应由模版自动生成
    /// </summary>
    public partial interface ISysUserRepository : IRepository<SysUser>
    { }
}

ISysUserInfoRepository.cs

using InjectExample.Component;
using InjectExample.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.Repositories
{
    /// <summary>
    ///   仓储操作层接口 此代码应由模版自动生成
    /// </summary>
    public partial interface ISysUserInfoRepository : IRepository<SysUserInfo>
    { }
}


SysUserRepository.cs

using InjectExample.Component;
using InjectExample.Model;
/* ==============================================================================
 * 功能描述:SysUserRepository 
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 11:21:51
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.Repositories.Impl
{
    /// <summary>
    ///   仓储操作层实现 此代码应由模版自动生成
    /// </summary>
    [Shared(Boundaries.DataConsistency)]
    [Export(typeof(ISysUserRepository))]
    internal partial class SysUserRepository : EfRepositoryBase<SysUser>, ISysUserRepository
    { }
}


SysUserInfoRepository.cs

using InjectExample.Component;
using InjectExample.Model;
/* ==============================================================================
 * 功能描述:SysUserInfoRepository
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 11:21:51
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.Repositories.Impl
{
    /// <summary>
    ///   仓储操作层实现 此代码应由模版自动生成
    /// </summary>
    [Shared(Boundaries.DataConsistency)]
    [Export(typeof(ISysUserInfoRepository))]
    internal partial class SysUserInfoRepository : EfRepositoryBase<SysUserInfo>, ISysUserInfoRepository
    { }
}


下面是真正的数据操作Service类,随便怎么写,这里演示两表连接查询方法 
ISysUserService.cs

using InjectExample.Model;
using InjectExample.Model.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.SysUsers
{
    public interface ISysUserService
    {
        SysUserVModel GetById(long id);
    }
}


SysUserService.cs,Service方法实现,引用Repository时,使用Import属性自动注入

using InjectExample.Core.Repositories;
using InjectExample.Model;
using InjectExample.Model.ViewModel;
/* ==============================================================================
 * 功能描述:SysUserService  
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 11:26:42
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.Core.SysUsers.Impl
{
    [Export(typeof(ISysUserService))]
    public class SysUserService : CoreServiceBase, ISysUserService
    {
        [Import]
        public ISysUserRepository SysUserRepository { get; set; }
        [Import]
        public ISysUserInfoRepository SysUserInfoRepository { get; set; }
        public SysUserVModel GetById(long id)
        {
            var user = (from u in SysUserRepository.Entities
                        join ui in SysUserInfoRepository.Entities
                            on u.ID equals ui.SysUserId
                        select new SysUserVModel
                        {
                            ID = u.ID,
                            Age = u.Age,
                            Name = u.Name,
                            Remark = u.Remark,
                            LoginCount = ui.LoginCount,
                            LastLoginTime = ui.LastLoginTime
                        }).FirstOrDefault();
            return user;
        }
    }
}


这里,Core层也完成了。

4、BLL逻辑处理层实现

BLL实现上,这里就是简单引用一下Service层的方法。 

ISysUserContract.cs

using InjectExample.Model;
using InjectExample.Model.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.BLL.SysUsers
{
    public interface ISysUserContract
    {
        SysUserVModel GetById(long id);
    }
}

SysUserContract.cs,引用 Service层时,也是使用 Import 属性自动注入

using InjectExample.Component;
using InjectExample.Core.SysUsers;
using InjectExample.Model;
using InjectExample.Model.ViewModel;
/* ==============================================================================
 * 功能描述:SysUserContract  
 * 创 建 者:蒲奎民
 * 创建日期:2016-08-29 11:32:59
 * CLR Version :4.0.30319.42000
 * ==============================================================================*/
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InjectExample.BLL.SysUsers.Impl
{
    [Export(typeof(ISysUserContract))]
    public class SysUserContract : ISysUserContract
    {
        [Import]
        public ISysUserService SysUserService { get; set; }
        public SysUserVModel GetById(long id)
        {
            if (id <= 0) throw new BusinessException("ID不正确!");
            return SysUserService.GetById(id);
        }
    }
}


BLL代码完成。

5、web表示层处理

因为依赖注入框架,内部用的是反射机制,所以在web运行后,首先要做的就是初始化加载dll,还有一些其他的内容。 
在Global.asax 的 Application_Start 方法中,调用方法初始化数据

        protected void Application_Start()
        {
            //禁用MVC响应标头
            MvcHandler.DisableMvcResponseHeader = true;
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            //MefInjectionProvider.Test();
            //Db初始化
            DatabaseInitializer.Initialize();
            DatabaseInitializer.PreCreateView();
        }

还有,依赖注入的初始化,继承于 IHttpModule ,所以在webconfig文件中加入注册代码,也能实现自动初始化,web.config加内容: 

    <modules>
      <add name="CompositionScopeModule" type="InjectExample.Component.Mvc.CompositionScopeModule" preCondition="managedHandler" />
      <add name="RemoveHttpHeadModule" type="InjectExample.Component.Mvc.RemoveHttpHeadModule" />
    </modules>


在App_Start下加FilterConfig.cs文件,内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace InjectExample.Web.App_Start
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    }
}

web.config加连接字符串:

  <connectionStrings>
    <add name="InjextExampleEntities" connectionString="Data Source=192.168.9.222;Initial Catalog=Example;Persist Security Info=True;User ID=dev;Password=123456;MultipleActiveResultSets=True;App=EntityFramework;" providerName="System.Data.SqlClient" />
  </connectionStrings>


然后,就可以运行了,再添加测试数据显示控制器和View页面: 

HomeController.cs

using InjectExample.BLL.SysUsers;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace InjectExample.Web.Controllers
{
    public class HomeController : Controller
    {
        [Import]
        public ISysUserContract SysUserContract { get; set; }
        //
        // GET: /Home/
        public ActionResult Index()
        {
            ViewBag.SysUser = SysUserContract.GetById(1);
            return View();
        }
    }
}

Index.cshtml

@{
    Layout = null;
    var model = ViewBag.SysUser as InjectExample.Model.ViewModel.SysUserVModel;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>这是测试首页</title>
</head>
<body>
    <div>
        这是测试首页<br />
        用户名称  @(model.Name)<br />
        用户年龄  @(model.Age)<br />
        登陆次数  @(model.LoginCount)<br />
        最后登陆  @(model.LastLoginTime)<br />
    </div>
</body>
</html>

这次可以显示测试数据了,附运行结果图: 



框架搭建完毕,此框架的使用,也是很方便,一般Model层、Core层的Configurations和Repositories中的代码,都可用CodeSmith等模版生成器自动生成,开发人员只需要实现具体的数据访问和逻辑处理层就可以在web中调用了,非常方便。 

这个框架搭建起来,比上一单的简单三层框架要复杂了很多,不过只要理解了,只是耗时多一点而已。


源码免费下地地址: 

http://download.csdn.net/detail/pukuimin1226/9616604  





版权声明:
作者:真爱无限 出处:http://www.pukuimin.top 本文为博主原创文章版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.
« 上一篇下一篇 »

相关文章:

评论列表:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。