ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构

前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多。主要集中增删该查每个模块都有,所以本次是为封装相同接口方法

   如果你想了解怎么重构普通的接口DAL层请查看第二节点

   如果你只想了解利用T4链接EF生成代码,可以忽略前两节,之后跳后最后T4模版的使用。

  (代码在最后)

   补充:

  最后必须让初学者理解一个知识点:分部类 partial 关键字,因为我们的重构是围绕分部类而实现,包括接口

partial 关键字指示可在命名空间中定义该类、结构或接口的其他部分。所有部分都必须使用 partial 关键字。在编译时,各个部分都必须可用来形成最终的类型。各个部分必须具有相同的可访问性,如 publicprivate 等。

如果将任意部分声明为抽象的,则整个类型都被视为抽象的。如果将任意部分声明为密封的,则整个类型都被视为密封的。如果任意部分声明基类型,则整个类型都将继承该类。

指定基类的所有部分必须一致,但忽略基类的部分仍继承该基类型。各个部分可以指定不同的基接口,最终类型将实现所有分部声明所列出的全部接口。在某一分部定义中声明的任何类、结构或接口成员可供所有其他部分使用。最终类型是所有部分在编译时的组合。

下列声明:

partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }

等效于下列声明:

class Earth : Planet, IRotate, IRevolve { }

知识点:

  1. 改变EF代码生成策略
    1. 改变生成策略为T4
    2. 添加TT模版
  2. 重构DAL层
    1. 创建ICommonRepository<T>接口
    2. 实现ICommonRepository<T>方法
  3. T4模版的使用

1.改变EF代码生成策略旧的ObjectContext改为T4(如果你的项目已经是DBContext API模式请跳过)(操作前备份项目)

在此之前我们也该改变一下代码生成策略,为什么会这个改变。这个项目我最初开始创建的时候用的EF版本为EF4.0当时EF4.0只提供了ObjectContext API接口模式

这个访问方式只能对于DataBase Frist用,不能用于Code Frist.所以一直用到这里,这个并不是很重要,最终都不会影响我们的功能开发

但是DBContext API的亮点,和现在教材都是基于DBContext策略的方式(EF4.1版本之后),我们有必要与时俱进。

操作方式很简单:

第一步:

从旧的ObjectContext改为T4(操作前备份项目)

第二步:

第三步:

->

最后看到DB.emdx下生成了很多模型类。根据表而生成的!这时代码编译将出错,根据出错的类库添加NUGET包。EntityFramework6.1.3版本,添加完之后还会继续报错。

因为ObjectContext有些方法和属性在DBContext已经不能用了

ObjectContext和ObjectSet都提供了AddObject的功能:

  比如 context.AddObject("Students", newStudent):

                  context.Students.AddObject(newStudent):  

           而 DBContext中则只有DBSet有这个功能,并且名称为成了Add

               context.Students.Add(newStudent): 

也包括DeleteObject,ObjectStateManager等。

(忽略所有错误。这些错误将在我们重构DAL层被解决)

2.重构DAL层,下面我们来看一张图

图中绿色部分为本次重构部分,再利用成T4连接EF 生成通用分部类部分。这样我们下次不用手动创建继承类,只需要创建其他操作的分部类,很是简单。来看代码才明白

在第一节下载17

讲代码

我们来看现有代码,以SysSample 模块的IDAL和DAL为例子

using Apps.Models;
using System.Linq;
namespace Apps.IDAL
{
    public interface ISysSampleRepository
    {
        IQueryable<SysSample> GetList(DBContainer db);
        int Create(SysSample entity);
        int Delete(string id);
        void Delete(DBContainer db, string[] deleteCollection);
        /// <param name="entity">实体</param>
        int Edit(SysSample entity);
        SysSample GetById(string id);
        bool IsExist(string id);
    }
}
using System;
using System.Linq;
using Apps.IDAL;
using Apps.Models;
using System.Data;

namespace Apps.DAL
{
    public class SysSampleRepository : ISysSampleRepository, IDisposable
    {
        public IQueryable<SysSample> GetList(DBContainer db)
        {
            IQueryable<SysSample> list = db.SysSample.AsQueryable();
            return list;
        }
        public int Create(SysSample entity)
        {
            using (DBContainer db = new DBContainer())
            {
                db.SysSample.AddObject(entity);
                return db.SaveChanges();
            }
        }
        public int Delete(string id)
        {
            using (DBContainer db = new DBContainer())
            {
                SysSample entity = db.SysSample.SingleOrDefault(a => a.Id == id);
                if (entity != null)
                {
                    
                    db.SysSample.DeleteObject(entity);
                }
                return db.SaveChanges();
            }
        }
        public int Delete(DBContainer db, string[] deleteCollection)
        {
            IQueryable<SysSample> collection = from f in db.SysSample
                                               where deleteCollection.Contains(f.Id)
                                               select f;
            foreach (var deleteItem in collection)
            {
                db.SysSample.DeleteObject(deleteItem);
            }
        }
        public int Edit(SysSample entity)
        {
            using (DBContainer db = new DBContainer())
            {
                db.SysSample.Attach(entity);
                db.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
                return db.SaveChanges();
            }
        }
        public SysSample GetById(string id)
        {
            using (DBContainer db = new DBContainer())
            {
                return db.SysSample.SingleOrDefault(a => a.Id == id);
            }
        }
        public bool IsExist(string id)
        {
            using (DBContainer db = new DBContainer())
            {
                SysSample entity = GetById(id);
                if (entity != null)
                    return true;
                return false;
            }
        }
        public void Dispose()
        {

        }
    }
}

看到我们其他模块也都必须实现类似代码。其中不同之处只有SysSample模型

好在.net提供索引访问对象的强类型List<T>这里的T代表SysSamle。是可变的

1.接下来我们实现通用接口在IDAL层

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Apps.IDAL
{
    public interface ICommonRepository<T> where T :class
    {
        bool Create(T model);
        bool Edit(T model);
        bool Delete(T model);
        /// <summary>
        /// 按主键删除
        /// </summary>
        /// <param name="keyValues"></param>
        int Delete(params object[] keyValues);
        T GetById(params object[] keyValues);
        /// <summary>
        /// 获得所有数据
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetList();
        /// <summary>
        /// 根据表达式获取数据
        /// </summary>
        /// <param name="whereLambda"></param>
        /// <returns></returns>
        IQueryable<T> GetList(Func<T, bool> whereLambda);bool IsExist(string id);
        int SaveChanges();
    }
}

代码解析:接口实现了增删改查通用接口,并声明 where T :class 【T必须是一个类(class)类型】

2.接下来我们实现通用方法DAL层 按照重构图所示,应该继承ICommonRepository接口,并实现接口方法

using Apps.IDAL;
using Apps.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Apps.DAL
{
    public abstract class CommonRepository<T> : ICommonRepository<T> where T:class
    {
        DBContainer db;
        public CommonRepository(DBContainer context)
        {
            this.db = context;
        }

        public DBContainer Context
        {
            get { return db; }
        }

        public virtual bool Create(T model)
        {
            db.Set<T>().Add(model);
            return db.SaveChanges()>0;
        }

        public virtual bool Edit(T model)
        {
            if (db.Entry<T>(model).State == EntityState.Modified)
            {
                return db.SaveChanges() > 0;
            }
            else if (db.Entry<T>(model).State == EntityState.Detached)
            {
                try
                {
                    db.Set<T>().Attach(model);
                    db.Entry<T>(model).State = EntityState.Modified;
                }
                catch (InvalidOperationException)
                {
                    //T old = Find(model._ID);
                    //db.Entry<old>.CurrentValues.SetValues(model);
                }
                return db.SaveChanges()>0;
            }
            return false;
        }

        public virtual bool Delete(T model)
        {
            db.Set<T>().Remove(model);
            return db.SaveChanges()>0;
        }

        public virtual int Delete(params object[] keyValues)
        {
            T model = GetById(keyValues);
            if(model!=null)
            {
                db.Set<T>().Remove(model);
                return db.SaveChanges();
            }
            return -1;
        }
        public virtual T GetById(params object[] keyValues)
        {
            return db.Set<T>().Find(keyValues);
        }

        public virtual IQueryable<T> GetList()
        {
            return db.Set<T>();
        }

        public virtual IQueryable<T> GetList(Func<T, bool> whereLambda)
        {
            return db.Set<T>().Where(whereLambda).AsQueryable();
        }
        public virtual bool IsExist(string id)
        {
            return GetById(id)!=null;
        }

        public int SaveChanges()
        {
           return db.SaveChanges();
        }
    }
}

 OK.全是DBContext API 操作EF方法。增删改查

3.T4生成分部类

接下来我们来看这么用这个接口

我们IDAL所有表(即模块)都要实现ICommonRepository接口好调用其中的增删改查做扩展

删掉ISysSampleRepository中的原来代码变为:

using Apps.Models;
using System.Linq;
namespace Apps.IDAL
{
    public interface ISysSampleRepository : ICommonRepository<SysSample>
    {
      
    }
}

观察到这里也是重复代码,因为同理我们所有表都要实现这样的接口,这样我们可以利用T4来生成这种的重复代码

我以前写过一篇文章是关于T4链接数据库的。构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(29)-T4模版

这里我们是直接链接edmx的。同理

1.新建一个文件夹。如下图所示并创建一个TT模版

创建后会产生2个文件。删掉Context.tt,因为在Apps.Models已经有了

 配置第五行的inputFile为上面所描述,可能因为环境不同你们EF路径有所不同。保存后TT模版会自动生成

tt模版如果没有高亮显示的。要安装一些工具。因为我是一边改一边发文章的。我这里也是没有的,下载T4Editor 安装高亮,什么版本就下什么就可以了(或者通过VS工具------扩展与更新 搜索)

http://t4-editor.tangible-engineering.com/Download_T4Editor_Plus_ModelingTools.html

tangible T4 Editor 2.3.0 plus modeling tools for Visual Studio 2015Download from Visual Studio Gallery

tangible T4 Editor 2.3.0 plus modeling tools for Visual Studio 2013Download from Visual Studio Gallery

按照ISysSampleRepository接口为例子。修改TT模版后代码

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF6.Utility.CS.ttinclude"#><#@ 
 output extension=".cs"#><#

const string inputFile = @"../../Apps.Models/DB.edmx";
var textTransform = DynamicTextTransformation.Create(this);
var code = new CodeGenerationTools(this);
var ef = new MetadataTools(this);
var typeMapper = new TypeMapper(code, ef, textTransform.Errors);
var    fileManager = EntityFrameworkTemplateFileManager.Create(this);
var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef);

if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile))
{
    return string.Empty;
}

WriteHeader(codeStringGenerator, fileManager);

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
{
    fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
#>
using Apps.Models;
namespace Apps.IDAL
{
    public partial interface I<#=entity.Name #>Repository:ICommonRepository<<#=entity.Name #>>
    {
    
    }
<#
    EndNamespace(code);
}

fileManager.Process();

#>
<#+

public void WriteHeader(CodeStringGenerator codeStringGenerator, EntityFrameworkTemplateFileManager fileManager)
{
    fileManager.StartHeader();
#>
//------------------------------------------------------------------------------
// <auto-generated>
// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#>
//
// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#>
// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#>
// </auto-generated>
//------------------------------------------------------------------------------
<#=codeStringGenerator.UsingDirectives(inHeader: true)#>
<#+
    fileManager.EndBlock();
}

public void BeginNamespace(CodeGenerationTools code)
{
    var codeNamespace = code.VsNamespaceSuggestion();
    if (!String.IsNullOrEmpty(codeNamespace))
    {
#>
namespace <#=code.EscapeNamespace(codeNamespace)#>
{
<#+
        PushIndent("    ");
    }
}

public void EndNamespace(CodeGenerationTools code)
{
    if (!String.IsNullOrEmpty(code.VsNamespaceSuggestion()))
    {
        PopIndent();
#>
}
<#+
    }
}

public const string TemplateId = "CSharp_DbContext_Types_EF6";

public class CodeStringGenerator
{
    private readonly CodeGenerationTools _code;
    private readonly TypeMapper _typeMapper;
    private readonly MetadataTools _ef;

    public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef)
    {
        ArgumentNotNull(code, "code");
        ArgumentNotNull(typeMapper, "typeMapper");
        ArgumentNotNull(ef, "ef");

        _code = code;
        _typeMapper = typeMapper;
        _ef = ef;
    }

    public string Property(EdmProperty edmProperty)
    {
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} {1} {2} {{ {3}get; {4}set; }}",
            Accessibility.ForProperty(edmProperty),
            _typeMapper.GetTypeName(edmProperty.TypeUsage),
            _code.Escape(edmProperty),
            _code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
            _code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
    }

    public string NavigationProperty(NavigationProperty navProp)
    {
        var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType());
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} {1} {2} {{ {3}get; {4}set; }}",
            AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)),
            navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
            _code.Escape(navProp),
            _code.SpaceAfter(Accessibility.ForGetter(navProp)),
            _code.SpaceAfter(Accessibility.ForSetter(navProp)));
    }
    
    public string AccessibilityAndVirtual(string accessibility)
    {
        return accessibility + (accessibility != "private" ? " virtual" : "");
    }
    
    public string EntityClassOpening(EntityType entity)
    {
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} {1}partial class {2}{3}",
            Accessibility.ForType(entity),
            _code.SpaceAfter(_code.AbstractOption(entity)),
            _code.Escape(entity),
            _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)));
    }
    
    public string EnumOpening(SimpleType enumType)
    {
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} enum {1} : {2}",
            Accessibility.ForType(enumType),
            _code.Escape(enumType),
            _code.Escape(_typeMapper.UnderlyingClrType(enumType)));
        }
    
    public void WriteFunctionParameters(EdmFunction edmFunction, Action<string, string, string, string> writeParameter)
    {
        var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef);
        foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable))
        {
            var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null";
            var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")";
            var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))";
            writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit);
        }
    }
    
    public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace)
    {
        var parameters = _typeMapper.GetParameters(edmFunction);
        
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} IQueryable<{1}> {2}({3})",
            AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)),
            _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace),
            _code.Escape(edmFunction),
            string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()));
    }
    
    public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace)
    {
        var parameters = _typeMapper.GetParameters(edmFunction);
        
        return string.Format(
            CultureInfo.InvariantCulture,
            "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});",
            _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace),
            edmFunction.NamespaceName,
            edmFunction.Name,
            string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()),
            _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())));
    }
    
    public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)
    {
        var parameters = _typeMapper.GetParameters(edmFunction);
        var returnType = _typeMapper.GetReturnType(edmFunction);

        var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray());
        if (includeMergeOption)
        {
            paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption";
        }

        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} {1} {2}({3})",
            AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)),
            returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">",
            _code.Escape(edmFunction),
            paramList);
    }
    
    public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)
    {
        var parameters = _typeMapper.GetParameters(edmFunction);
        var returnType = _typeMapper.GetReturnType(edmFunction);

        var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()));
        if (includeMergeOption)
        {
            callParams = ", mergeOption" + callParams;
        }
        
        return string.Format(
            CultureInfo.InvariantCulture,
            "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});",
            returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">",
            edmFunction.Name,
            callParams);
    }
    
    public string DbSet(EntitySet entitySet)
    {
        return string.Format(
            CultureInfo.InvariantCulture,
            "{0} virtual DbSet<{1}> {2} {{ get; set; }}",
            Accessibility.ForReadOnlyProperty(entitySet),
            _typeMapper.GetTypeName(entitySet.ElementType),
            _code.Escape(entitySet));
    }

    public string UsingDirectives(bool inHeader, bool includeCollections = true)
    {
        return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
            ? string.Format(
                CultureInfo.InvariantCulture,
                "{0}using System;{1}" +
                "{2}",
                inHeader ? Environment.NewLine : "",
                includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
                inHeader ? "" : Environment.NewLine)
            : "";
    }
}

public class TypeMapper
{
    private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName";

    private readonly System.Collections.IList _errors;
    private readonly CodeGenerationTools _code;
    private readonly MetadataTools _ef;

    public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors)
    {
        ArgumentNotNull(code, "code");
        ArgumentNotNull(ef, "ef");
        ArgumentNotNull(errors, "errors");

        _code = code;
        _ef = ef;
        _errors = errors;
    }

    public static string FixNamespaces(string typeName)
    {
        return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial.");
    }

    public string GetTypeName(TypeUsage typeUsage)
    {
        return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null);
    }

    public string GetTypeName(EdmType edmType)
    {
        return GetTypeName(edmType, isNullable: null, modelNamespace: null);
    }

    public string GetTypeName(TypeUsage typeUsage, string modelNamespace)
    {
        return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace);
    }

    public string GetTypeName(EdmType edmType, string modelNamespace)
    {
        return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace);
    }

    public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace)
    {
        if (edmType == null)
        {
            return null;
        }

        var collectionType = edmType as CollectionType;
        if (collectionType != null)
        {
            return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace));
        }

        var typeName = _code.Escape(edmType.MetadataProperties
                                .Where(p => p.Name == ExternalTypeNameAttributeName)
                                .Select(p => (string)p.Value)
                                .FirstOrDefault())
            ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ?
                _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) :
                _code.Escape(edmType));

        if (edmType is StructuralType)
        {
            return typeName;
        }

        if (edmType is SimpleType)
        {
            var clrType = UnderlyingClrType(edmType);
            if (!IsEnumType(edmType))
            {
                typeName = _code.Escape(clrType);
            }

            typeName = FixNamespaces(typeName);

            return clrType.IsValueType && isNullable == true ?
                String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) :
                typeName;
        }

        throw new ArgumentException("edmType");
    }
    
    public Type UnderlyingClrType(EdmType edmType)
    {
        ArgumentNotNull(edmType, "edmType");

        var primitiveType = edmType as PrimitiveType;
        if (primitiveType != null)
        {
            return primitiveType.ClrEquivalentType;
        }

        if (IsEnumType(edmType))
        {
            return GetEnumUnderlyingType(edmType).ClrEquivalentType;
        }

        return typeof(object);
    }
    
    public object GetEnumMemberValue(MetadataItem enumMember)
    {
        ArgumentNotNull(enumMember, "enumMember");
        
        var valueProperty = enumMember.GetType().GetProperty("Value");
        return valueProperty == null ? null : valueProperty.GetValue(enumMember, null);
    }
    
    public string GetEnumMemberName(MetadataItem enumMember)
    {
        ArgumentNotNull(enumMember, "enumMember");
        
        var nameProperty = enumMember.GetType().GetProperty("Name");
        return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null);
    }

    public System.Collections.IEnumerable GetEnumMembers(EdmType enumType)
    {
        ArgumentNotNull(enumType, "enumType");

        var membersProperty = enumType.GetType().GetProperty("Members");
        return membersProperty != null 
            ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null)
            : Enumerable.Empty<MetadataItem>();
    }
    
    public bool EnumIsFlags(EdmType enumType)
    {
        ArgumentNotNull(enumType, "enumType");
        
        var isFlagsProperty = enumType.GetType().GetProperty("IsFlags");
        return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null);
    }

    public bool IsEnumType(GlobalItem edmType)
    {
        ArgumentNotNull(edmType, "edmType");

        return edmType.GetType().Name == "EnumType";
    }

    public PrimitiveType GetEnumUnderlyingType(EdmType enumType)
    {
        ArgumentNotNull(enumType, "enumType");

        return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null);
    }

    public string CreateLiteral(object value)
    {
        if (value == null || value.GetType() != typeof(TimeSpan))
        {
            return _code.CreateLiteral(value);
        }

        return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks);
    }
    
    public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable<string> types, string sourceFile)
    {
        ArgumentNotNull(types, "types");
        ArgumentNotNull(sourceFile, "sourceFile");
        
        var hash = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
        if (types.Any(item => !hash.Add(item)))
        {
            _errors.Add(
                new CompilerError(sourceFile, -1, -1, "6023",
                    String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict"))));
            return false;
        }
        return true;
    }
    
    public IEnumerable<SimpleType> GetEnumItemsToGenerate(IEnumerable<GlobalItem> itemCollection)
    {
        return GetItemsToGenerate<SimpleType>(itemCollection)
            .Where(e => IsEnumType(e));
    }
    
    public IEnumerable<T> GetItemsToGenerate<T>(IEnumerable<GlobalItem> itemCollection) where T: EdmType
    {
        return itemCollection
            .OfType<T>()
            .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName))
            .OrderBy(i => i.Name);
    }

    public IEnumerable<string> GetAllGlobalItems(IEnumerable<GlobalItem> itemCollection)
    {
        return itemCollection
            .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i))
            .Select(g => GetGlobalItemName(g));
    }

    public string GetGlobalItemName(GlobalItem item)
    {
        if (item is EdmType)
        {
            return ((EdmType)item).Name;
        }
        else
        {
            return ((EntityContainer)item).Name;
        }
    }

    public IEnumerable<EdmProperty> GetSimpleProperties(EntityType type)
    {
        return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type);
    }
    
    public IEnumerable<EdmProperty> GetSimpleProperties(ComplexType type)
    {
        return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type);
    }
    
    public IEnumerable<EdmProperty> GetComplexProperties(EntityType type)
    {
        return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type);
    }
    
    public IEnumerable<EdmProperty> GetComplexProperties(ComplexType type)
    {
        return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type);
    }

    public IEnumerable<EdmProperty> GetPropertiesWithDefaultValues(EntityType type)
    {
        return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null);
    }
    
    public IEnumerable<EdmProperty> GetPropertiesWithDefaultValues(ComplexType type)
    {
        return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null);
    }

    public IEnumerable<NavigationProperty> GetNavigationProperties(EntityType type)
    {
        return type.NavigationProperties.Where(np => np.DeclaringType == type);
    }
    
    public IEnumerable<NavigationProperty> GetCollectionNavigationProperties(EntityType type)
    {
        return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
    }
    
    public FunctionParameter GetReturnParameter(EdmFunction edmFunction)
    {
        ArgumentNotNull(edmFunction, "edmFunction");

        var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters");
        return returnParamsProperty == null
            ? edmFunction.ReturnParameter
            : ((IEnumerable<FunctionParameter>)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault();
    }

    public bool IsComposable(EdmFunction edmFunction)
    {
        ArgumentNotNull(edmFunction, "edmFunction");

        var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute");
        return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null);
    }

    public IEnumerable<FunctionImportParameter> GetParameters(EdmFunction edmFunction)
    {
        return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef);
    }

    public TypeUsage GetReturnType(EdmFunction edmFunction)
    {
        var returnParam = GetReturnParameter(edmFunction);
        return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage);
    }
    
    public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption)
    {
        var returnType = GetReturnType(edmFunction);
        return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType;
    }
}

public static void ArgumentNotNull<T>(T arg, string name) where T : class
{
    if (arg == null)
    {
        throw new ArgumentNullException(name);
    }
}
#>

核心代码解析:

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
{
    fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
#>
using Apps.Models;
namespace Apps.IDAL
{
    public partial interface I<#=entity.Name #>Repository:ICommonRepository<<#=entity.Name #>>
    {
    
    }
<#
    EndNamespace(code);
}

fileManager.Process();

#>

循环生成。达到预期效果

 TT模版里面太多代码很难看懂,需要看官方帮助文档才行。但是我们可以提取公共部分。以后写TT就引入。看图

在WriteHeder方法后都是通用的访问代码。我们提取之后的代码。因为安装了T4高亮。我只能调浅色,深色效果太差

在Apps.Models创建 Common.ttinclude来做公共部分(你可以创建在其他路径,到时候是引入路径为准)

最后修改:ICommonRepository.tt第二行代码:

<#@ include file="../../Apps.Models/Common.ttinclude"#><#@ 

OK。看起来间接很多了,以后创建其他tt文件就可以直接引用公共部分,如果不提取tt模版也是没有问题的。

同理我们创建DAL层的公共部分,生成后的代码如下,同样是一个分部类CommonRepository

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="../../Apps.Models/Common.ttinclude"#><#@ 
 output extension=".cs"#>
 <#

const string inputFile = @"../../Apps.Models/DB.edmx";
var textTransform = DynamicTextTransformation.Create(this);
var code = new CodeGenerationTools(this);
var ef = new MetadataTools(this);
var typeMapper = new TypeMapper(code, ef, textTransform.Errors);
var    fileManager = EntityFrameworkTemplateFileManager.Create(this);
var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef);

if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile))
{
    return string.Empty;
}

WriteHeader(codeStringGenerator, fileManager);

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
{
    fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
#>
using Apps.Models;
using Apps.DAL;
namespace Apps.IDAL
{
    public partial class <#=entity.Name #>Repository:CommonRepository<<#=entity.Name #>>
    {
        public <#=entity.Name #>Repository(DBContainer db):base(db)
        {
        
        }
    }
<#
    EndNamespace(code);
}

fileManager.Process();

#>
//------------------------------------------------------------------------------
// <auto-generated>
//     此代码已从模板生成。
//
//     手动更改此文件可能导致应用程序出现意外的行为。
//     如果重新生成代码,将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------

using Apps.Models;
using Apps.DAL;
namespace Apps.IDAL
{
    public partial class SysSampleRepository:CommonRepository<SysSample>
    {
        public SysSampleRepository(DBContainer db):base(db)
        {
        
        }
    }
}

接下来原来很长的ISysSampleRepository接口最后变成了一个分部接口

using Apps.Models;
using System.Linq;
namespace Apps.IDAL
{
    public partial interface ISysSampleRepository
    {
       //处理通用部分外的业务
    }
}

SysSampleRepository变成了一个分部类

using System;
using System.Linq;
using Apps.IDAL;
using Apps.Models;
using System.Data;

namespace Apps.DAL
{
    public class SysSampleRepository
    {

可以处理通用部分外的业务

这样我们关注点真的很专注了。Ye...

关于业务层,肯定还是报错的状态,这时候我们就来修改一下

例如:

变为

最后业务层代码:

//------------------------------------------------------------------------------
// <auto-generated>
//     此代码由T4模板自动生成
//       生成时间 2013-04-22 10:41:47 by App
//     对此文件的更改可能会导致不正确的行为,并且如果
//     重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Unity;
using Apps.Models;
using Apps.Common;
using System.Transactions;
using Apps.Models.Sys;
using Apps.IBLL;
using Apps.IDAL;
using Apps.BLL.Core;
using Apps.Locale;

namespace Apps.BLL
{
    public class SysSampleBLL : BaseBLL, ISysSampleBLL
    {

        [Dependency]
        public ISysSampleRepository m_Rep { get; set; }

        public List<SysSampleModel> GetList(ref GridPager pager, string queryStr)
        {

            IQueryable<SysSample> queryData = null;
            if (!string.IsNullOrWhiteSpace(queryStr))
            {
                queryData = m_Rep.GetList(a => a.Name.Contains(queryStr) || a.Note.Contains(queryStr));
            }
            else
            {
                queryData = m_Rep.GetList();
            }
            pager.totalRows = queryData.Count();
            //排序
            queryData = LinqHelper.SortingAndPaging(queryData, pager.sort, pager.order, pager.page, pager.rows);
            return CreateModelList(ref queryData);
        }
        private List<SysSampleModel> CreateModelList(ref IQueryable<SysSample> queryData)
        {

            List<SysSampleModel> modelList = (from r in queryData
                                              select new SysSampleModel
                                              {
                                                  Id = r.Id,
                                                  Name = r.Name,
                                                  Age = r.Age,
                                                  Bir = r.Bir,
                                                  Photo = r.Photo,
                                                  Note = r.Note,
                                                  CreateTime = r.CreateTime,

                                              }).ToList();

            return modelList;
        }

        public bool Create(ref ValidationErrors errors, SysSampleModel model)
        {
            try
            {
                SysSample entity = m_Rep.GetById(model.Id);
                if (entity != null)
                {
                    errors.Add(Resource.PrimaryRepeat);
                    return false;
                }
                entity = new SysSample();
                entity.Id = model.Id;
                entity.Name = model.Name;
                entity.Age = model.Age;
                entity.Bir = model.Bir;
                entity.Photo = model.Photo;
                entity.Note = model.Note;
                entity.CreateTime = model.CreateTime;

                if (m_Rep.Create(entity))
                {
                    return true;
                }
                else
                {
                    errors.Add(Resource.InsertFail);
                    return false;
                }
            }
            catch (Exception ex)
            {
                errors.Add(ex.Message);
                ExceptionHander.WriteException(ex);
                return false;
            }
        }

        public bool Delete(ref ValidationErrors errors, string id)
        {
            try
            {
                if (m_Rep.Delete(id) == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                errors.Add(ex.Message);
                ExceptionHander.WriteException(ex);
                return false;
            }
        }

        public bool Delete(ref ValidationErrors errors, string[] deleteCollection)
        {
            try
            {
                if (deleteCollection != null)
                {
                    using (TransactionScope transactionScope = new TransactionScope())
                    {

                        m_Rep.Delete(deleteCollection);
                        if (db.SaveChanges() == deleteCollection.Length)
                        {
                            transactionScope.Complete();
                            return true;
                        }
                        else
                        {
                            Transaction.Current.Rollback();
                            return false;
                        }
                    }
                }
                return false;
            }
            catch (Exception ex)
            {
                errors.Add(ex.Message);
                ExceptionHander.WriteException(ex);
                return false;
            }
        }

        public bool Edit(ref ValidationErrors errors, SysSampleModel model)
        {
            try
            {
                SysSample entity = m_Rep.GetById(model.Id);
                if (entity == null)
                {
                    errors.Add(Resource.Disable);
                    return false;
                }
                entity.Name = model.Name;
                entity.Age = model.Age;
                entity.Bir = model.Bir;
                entity.Photo = model.Photo;
                entity.Note = model.Note;


                if (m_Rep.Edit(entity))
                {
                    return true;
                }
                else
                {
                    errors.Add(Resource.EditFail);
                    return false;
                }

            }
            catch (Exception ex)
            {
                errors.Add(ex.Message);
                ExceptionHander.WriteException(ex);
                return false;
            }
        }

        public bool IsExists(string id)
        {
            if (db.SysSample.SingleOrDefault(a => a.Id == id) != null)
            {
                return true;
            }
            return false;
        }

        public SysSampleModel GetById(string id)
        {
            if (IsExist(id))
            {
                SysSample entity = m_Rep.GetById(id);
                SysSampleModel model = new SysSampleModel();
                model.Id = entity.Id;
                model.Name = entity.Name;
                model.Age = entity.Age;
                model.Bir = entity.Bir;
                model.Photo = entity.Photo;
                model.Note = entity.Note;
                model.CreateTime = entity.CreateTime;

                return model;
            }
            else
            {
                return null;
            }
        }

        public bool IsExist(string id)
        {
            return m_Rep.IsExist(id);
        }
    }
}

--------------------------------------------------------------------------------写在最后--------------------------------------------------------------------------------

可以对比以前DAL层的代码,明显的减少很多(虽然业务层没有减少)。也许在以后业务层也有必要的重构!

最后我完全修改了我项目的DAL层。用数据直接说话

整整少了两万行。却完成了相同的功能。(代码类型.cs,与事实可能有点差别,但是可以效果明显)

代码参考下载。重构后的架构(VS2013)执行根目录下的script.sql脚本。并修改web.config数据库链接即可查看

如查看重构前代码可以到第一节下载17节代码

https://yunpan.cn/cYUdjssbmiLrL  提取码 e622

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏马洪彪

C#获取AD域中计算机和用户的信息

如果你的计算机加入了某个AD域,则可以获取该域中所有的计算机和用户的信息。 所用程序集,需要.Net Framework 4。 添加程序集引用 System.D...

39370
来自专栏Porschev[钟慰]的专栏

前台JS(Jquery)调用后台方法 无刷新级联菜单示例

前台用AJAX直接调用后台方法,老有人发帖提问,没事做个示例 CasMenu.aspx页面: <%@ Page Language="C#" AutoEventW...

35950
来自专栏菩提树下的杨过

msmq发送速度的测试

在一些并发量比较高的"中小型"应用中,如果短期内有大量的数据插入,利用msmq中转是一个不错的选择(petshop就是这么干的),想知道msmq一秒钟内到底能...

25790
来自专栏飞扬的花生

Html5上传插件封装

      前段时间将flash的上传控件替换成使用纯js实现的,在此记录 1.创建标签 <div class="camera-area" style="dis...

41180
来自专栏跟着阿笨一起玩NET

关于asp.net与winform导出excel的代码

一、asp.net中导出Execl的方法: 在asp.net中导出Execl有两种方法,一种是将导出的文件存放在服务器某个文件夹下面,然后将文件地址输出在...

12010
来自专栏魏琼东

本人为巨杉数据库(开源NoSQL)写的C#驱动,支持Linq,全部开源,已提交github

     这些年在做AgileEAS.NET SOA 中间件平台的推广、技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能...

11500
来自专栏GreenLeaves

WCF系列教程之WCF客户端异常处理

本文参考自:http://www.cnblogs.com/wangweimutou/p/4414393.html,纯属读书笔记,加深记忆 一、简介 当我们打开W...

21260
来自专栏木宛城主

两天完成一个小型工程报价系统(三层架构)

花了两天,整理了一下三层架构,顺便练了一个小型三层架构——工程报价系统。 功能很简单,完成基本的增删改查 搭建项目三层结构 ? 界面的设计以及美化 ...

35790
来自专栏大内老A

谈谈WCF中的Data Contract(4):WCF Data Contract Versioning

软件工程是一门独特的工程艺术,需要解决的是不断改变的需求变化。而对于WCF,对于SOA,由于涉及的是对多个系统之间的交互问题,如何有效地解决不断改变的需求所带来...

25450
来自专栏ASP.NET MVC5 后台权限管理系统

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(23)-权限管理系统-角色组模块

接下来我们的目标是 角色组管理 角色组权限设置 用户管理 把角色组授权给用户 给用户分配角色组 所以最少我们还要讲多5讲才能结束这个管理系统,经过之前的样例程序...

33790

扫码关注云+社区

领取腾讯云代金券