Entity Framework 三层架构--持久层使用封装之实现类DaoTemplate

下面是关键的实现代码,由于有注释我不再赘述:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.Data;
using System.Data.EntityClient;
using System.Data.Metadata.Edm;
using System.Data.Mapping;
using System.Reflection;
using System.Collections;
using System.Threading;
using System.Data.Objects;
using System.Runtime.Serialization;
using System.Configuration;
using System.Data.Common;
using System.Linq.Expressions;

namespace EFLabModelFirst.JT.Dao
{
    public delegate object EFCallBackHandler(ObjectContext em);
    public delegate TResult EFSelectCallBackHandler<IQueryable, TResult>(IQueryable query);

    /// <summary>
    /// 摘要:
    ///     Entity Framework封装类,简化访问
    ///     请不要随意修改这个类
    /// xxx.Config参考配置:
    ///     <configuration>
    ///        <appSettings>
    ///            <!--连接字符串的名称-->
    ///            <add key="ConnectionStringKey" value="modelfirstEntities"/>
    ///            <!--实体容器的名称-->
    ///            <add key="EntityContainerName" value="modelfirstEntities"/>
    ///            <!--对象上下文类型-->
    ///            <add key="ObjectContextType" value="EFLabModelFirst.modelfirstEntities"/>
    ///        </appSettings>
    ///      <connectionStrings>
    ///        <add name="modelfirstEntities" connectionString="metadata=res://*/ModelFirst.csdl|res://*/ModelFirst.ssdl|res://*/ModelFirst.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\sqlexpress;Initial Catalog=modelfirst;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
    ///      </connectionStrings>
    ///     </configuration>
    /// </summary>
    public class DaoTemplate
    {
        [ThreadStatic]
        private static ObjectContext _em = null;
        /// <summary>
        /// 对象上下文,每个线程访问该属性可以获得一个单独的实例
        /// </summary>
        private static  ObjectContext EM
        {
            get
            {
                if (_em == null)
                {
                    try
                    {
                        _em = Activator.CreateInstance(Type.GetType(ObjectContextType), ConfigurationManager.ConnectionStrings[ConnectionStringKey].ConnectionString, EntityContainerName) as ObjectContext;
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("创建ObjectContext失败,可能是在模型代码后置文件\"xxx.Designer.cs\"里面没有找到需要手动添加的构造函数,比如:public modelfirstEntities(string connectionString,string defaultContainerName):base(connectionString,defaultContainerName)",ex);
                    }
                    if (_em == null)
                        throw new Exception("创建ObjectContext失败,原因不明");
                }

                return _em;
            }
        }

        /// <summary>
        /// 连接字符串key
        /// </summary>
        static readonly string ConnectionStringKey = string.Empty;
        /// <summary>
        /// 实体容器名称
        /// </summary>
        static readonly string EntityContainerName = string.Empty;
        /// <summary>
        /// 对象上下文名称
        /// </summary>
        static readonly string ObjectContextType = string.Empty;

        /// <summary>
        /// 存储所有实体类名和实体集名称的映射
        /// Key:实体类型名称
        /// Value:实体集名称
        /// </summary>
        public static readonly Dictionary<String, String> EntitySetNameMap = new Dictionary<String, String>();

        /// <summary>
        /// 静态代码块,所有线程执行前该方法有且仅有执行一次
        /// </summary>
        static DaoTemplate()
        {
            ObjectContextType = ConfigurationManager.AppSettings["ObjectContextType"];
            ConnectionStringKey = ConfigurationManager.AppSettings["ConnectionStringKey"];
            EntityContainerName = ConfigurationManager.AppSettings["EntityContainerName"];
            if (string.IsNullOrEmpty(ObjectContextType))
                throw new Exception("xxx.Config文件\"appSettings节\"没有配置ObjectContext");
            if (string.IsNullOrEmpty(ConnectionStringKey))
                throw new Exception("xxx.Config文件\"connectionStrings节\"没有配置连接字符串");
            if (string.IsNullOrEmpty(EntityContainerName))
                throw new Exception("xxx.Config文件\"appSettings节\"没有配置实体容器名称");

            //构建连接对象
            EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings[ConnectionStringKey].ConnectionString);
            string[] arrstr = ecsb.Metadata.Split('|');//得到映射文件
            EdmItemCollection e = new EdmItemCollection(arrstr[0]);//得到CSDL
            StoreItemCollection s = new StoreItemCollection(arrstr[1]);//得到SSDL
            StorageMappingItemCollection smt = new StorageMappingItemCollection(e, s, arrstr[2]);//得到MSL
            //获取合部实体对应关系
            var entities = smt[0].GetType().GetProperty("EntitySetMaps", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(smt[0], null);
            //反射得到StorageSetMapping类型
            Assembly ass = Assembly.Load("System.Data.Entity,Version=3.5.0.0,culture=Neutral,PublicKeyToken=b77a5c561934e089");
            Type type = ass.GetType("System.Data.Mapping.StorageSetMapping");
            foreach (var entityvalue in (IList)entities)
            {
                var p = entityvalue.GetType().GetField("m_extent", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);

                EntitySet es = (EntitySet)type.GetField("m_extent", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(entityvalue);
                EntitySetNameMap.Add(es.ElementType.Name, es.Name);
            }
        }

        /// <summary>
        /// 提交保存
        /// </summary>
        public void Commit()
        {
            EM.SaveChanges();
        }

        /// <summary>
        /// 获得一个实体的主键名称
        /// </summary>
        /// <param name="entityType">实体类的类型信息对象</param>
        /// <returns>主键名称</returns>
        public virtual string GetKeyName(Type entityType)
        {
            foreach (var pi in entityType.GetProperties())
            {
                var attr = pi.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).FirstOrDefault()
                    as EdmScalarPropertyAttribute;
                if (attr != null &&
                    pi.GetCustomAttributes(typeof(DataMemberAttribute), false).FirstOrDefault() != null &&
                    attr.EntityKeyProperty)
                    return pi.Name;
            }
            return string.Empty;
        }


        /// <summary>
        /// 添加一个对象
        /// </summary>
        /// <param name="obj">待添加的对象</param>
        public virtual void AddObject(Object obj)
        {
            EM.AddObject(EntitySetNameMap[obj.GetType().Name], obj);
            EM.SaveChanges();
        }

        /// <summary>
        /// 删除一个对象
        /// </summary>
        /// <param name="obj">待删除的对象</param>
        public virtual void DeleteObject(Object obj)
        {
            EM.AttachTo(EntitySetNameMap[obj.GetType().Name], obj);
            EM.DeleteObject(obj);
            EM.SaveChanges();
        }

        /// <summary>
        /// 获得一个实体
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="keyValue">主键值</param>
        /// <returns>查询到的对象</returns>
        public virtual T GetEntityByKey<T>(object keyValue) where T : class
        {
            return
                EM.GetObjectByKey(new EntityKey(EntityContainerName + "." + EntitySetNameMap[typeof(T).Name], GetKeyName(typeof(T)), keyValue)) as T;
        }

        /// <summary>
        /// 根据条件获取某个对象
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="where">查询条件</param>
        /// <returns>实体</returns>
        public virtual T GetEntity<T>(Expression<Func<T, bool>> where) where T : class
        {
            return EM.CreateObjectSet<T>().Where(where).FirstOrDefault();
        }

       /// <summary>
        /// 该函数已过期,根据条件获取某个值,比如聚合函数查询,
       /// </summary>
       /// <typeparam name="T">类型</typeparam>
       /// <typeparam name="TResult">查询结果了性</typeparam>
       /// <param name="where">查询条件</param>
       /// <param name="selector">投影表达式树</param>
       /// <returns></returns>
        //public virtual TResult GetObject<T, TResult>(Expression<Func<T, bool>> where, Expression<Func<T, TResult>> selector) where T : class
        //{
        //    return EM.CreateObjectSet<T>().Where<T>(where).Select<T, TResult>(selector).FirstOrDefault<TResult>();
        //}
       
        /// <summary>
        /// 根据条件获取某个值,比如聚合函数查询
        /// </summary>
        /// <typeparam name="T">被查询的类型</typeparam>
        /// <typeparam name="TResult">查询结果类型</typeparam>
        /// <param name="where">查询条件</param>
        /// <param name="includes">要抓取的导航属性数组</param>
        /// <param name="selectHandler">投影委托</param>
        /// <returns>查询结果</returns>
        public virtual TResult GetObject<T, TResult>(EFSelectCallBackHandler<IQueryable<T>, TResult> selectHandler,Expression<Func<T, bool>> where, params string[] includes) where T : class
        {
            if (selectHandler == null)
                throw new Exception("委托EFSelectCallBackHandler不能为空");
            IQueryable<T> query = EM.CreateObjectSet<T>();
            if (includes == null || includes.Length == 0)
                query = query.Where<T>(where == null ? t => true : where);
            else
            {
                foreach (var include in includes)
                {
                    if (string.IsNullOrEmpty(include))
                        continue;
                    query = (query as ObjectQuery<T>).Include(include);
                }
            }
            
            return selectHandler(query);
        }

        /// <summary>
        /// 根据条件获取某个值,比如聚合函数查询
        /// </summary>
        /// <typeparam name="T">被查询的类型</typeparam>
        /// <typeparam name="TResult">查询结果类型</typeparam>
        /// <param name="includes">要抓取的导航属性数组</param>
        /// <param name="selectHandler">投影委托</param>
        /// <returns>查询结果</returns>
        public virtual TResult GetObject<T, TResult>(EFSelectCallBackHandler<IQueryable<T>, TResult> selectHandler,params string[] includes) where T : class
        {
            return GetObject<T, TResult>(selectHandler, null, includes);
        }

        /// <summary>
        /// 根据实体的实体键修改实体
        /// </summary>
        /// <param name="obj"></param>
        public virtual void UpdateObject(object obj)
        {
            EM.AttachTo(EntitySetNameMap[obj.GetType().Name], obj);
            EM.ObjectStateManager.ChangeObjectState(obj, EntityState.Modified);
            EM.SaveChanges();
        }

        /// <summary>
        /// 根据条件进行查询
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="where">查询条件</param>
        /// <returns>符号条件的实体的集合</returns>
        public ICollection<T> FindList<T>(Func<T, bool> where) where T : class
        {

            return EM.CreateObjectSet<T>().Where<T>(where).AsEnumerable().ToList();

        }
        /// <summary>
        /// 根据多个条件进行查询
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="where">查询条件</param>
        /// <returns>符合条件的实体的集合</returns>
        public ICollection<T> FindList<T>(params Func<T, bool>[] where) where T : class
        {
            if (where != null && where.Length > 0)
            {
                IEnumerable<T> query = EM.CreateObjectSet<T>().Where(where[0]);
                for (int i = 1; i < where.Length; i++)
                {
                    query = query.Where(where[i]);
                }
                return query.ToList<T>();
            }
            return null;
        }

        /// <summary>
        /// 根据条件、排序、投影进行查找
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="TKey">排序属性类型</typeparam>
        /// <typeparam name="TResult">返回结果类型</typeparam>
        /// <param name="where">查询条件树</param>
        /// <param name="orderSelector">排序</param>
        /// <param name="selector">投影</param>
        /// <returns>符合条件的对象的集合</returns>
        public ICollection<TResult> FindList<T, TKey, TResult>(Expression<Func<T, bool>> where, Func<T, TKey> orderSelector, Func<T, TResult> selector) where T : class
        {

            return EM.CreateObjectSet<T>().Where<T>(where).OrderBy(orderSelector).Select(selector).ToList();

        }

        /// <summary>
        /// 根据条件和排序进行查找,带抓取功能
        /// </summary>
        /// <typeparam name="T">被查询的实体类型</typeparam>
        /// <typeparam name="TKey">排序属性的类型</typeparam>
        /// <typeparam name="TResult">查询结果类型</typeparam>
        /// <param name="where">查询条件</param>
        /// <param name="include">抓取属性</param>
        /// <param name="orderSelector">排序选择器</param>
        /// <param name="selector">投影选择器</param>
        /// <returns></returns>
        public ICollection<TResult> FindList<T, TKey, TResult>(Expression<Func<T, bool>> where,string include,Func<T, TKey> orderSelector, Func<T, TResult> selector) where T : class
        {   
            return EM.CreateObjectSet<T>().Include(include).Where<T>(where).OrderBy(orderSelector).Select(selector).ToList();

        }

        /// <summary>
        ///  执行原始SQL查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="commandText">要执行查询的SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <returns>符合条件的对象的集合</returns>
        public ICollection<T> ExecuteSqlQuery<T>(string commandText,params DbParameter[] parameters)
        {
            return
                EM.ExecuteStoreQuery<T>(commandText, parameters).ToList<T>();
        }

        /// <summary>
        /// 执行原始SQL命令
        /// </summary>
        /// <param name="commandText">SQL命令</param>
        /// <param name="parameters">参数</param>
        /// <returns>影响的记录数</returns>
        public int ExecuteSqlNonQuery(string commandText, params DbParameter[] parameters)
        {
            
            return
                EM.ExecuteStoreCommand(commandText, parameters);
        }

        /// <summary>
        /// 执行任何操作
        /// </summary>
        /// <param name="callBackHandler"></param>
        /// <returns></returns>
        protected object Execute(EFCallBackHandler callBackHandler)
        {
            return callBackHandler(EM);
        }
        /// <summary>
        /// 分页泛型方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="Tkey"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="pi"></param>
        public void Pager<T,Tkey,TResult>(PageInfo<T,Tkey,TResult> pi) where T:class
        {
            ObjectSet<T> os = EM.CreateObjectSet<T>();

            IQueryable<T> query = null;
            if (!string.IsNullOrEmpty(pi.Include))
                query = os.Include(pi.Include);
            else
                query = os.AsQueryable<T>();
  
            query = query.Where<T>(pi.Where == null ? t => true : pi.Where);
                    
            //总条数
            pi.RecordCount = query.LongCount();
            //总页数
            pi.PageCount = pi.RecordCount % pi.PageSize == 0 ? pi.RecordCount / pi.PageSize : pi.RecordCount / pi.PageSize + 1;

            query = query                
                    .OrderBy<T, Tkey>(pi.Order == null ? t => default(Tkey) : pi.Order)
                    .Skip<T>((pi.PageIndex - 1) * pi.PageSize)
                    .Take<T>(pi.PageSize);
            if (pi.Select != null)
                pi.List = query.Select<T, TResult>(pi.Select).ToList<TResult>();
            else
                pi.List = query.ToList<T>() as ICollection<TResult>;
                
        }

    }
}

我们来看看这个DaoTemplate的子类PublisherDao类的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Linq.Expressions;

namespace EFLabModelFirst.JT.Dao
{
    /// <summary>
    /// 有关于出版社的查询示范,
    /// </summary>
    public class PublisherDao:DaoTemplate
    {
        /// <summary>
        /// sql查询
        /// </summary>
        public void Find1()
        {
            ICollection<Publisher> plist = 
                ExecuteSqlQuery<Publisher>("SELECT * FROM Publishers AS P WHERE SUBSTRING(P.PublisherName,LEN(P.PublisherName)-2,3)=@Suffix", new SqlParameter("@Suffix", "出版社"));
            foreach (var item in plist)
            {
                Console.WriteLine(item.PublisherID+"\t"+item.PublisherName);
            }
        }

        /// <summary>
        /// 手工工造表达式示范
        /// </summary>
        public void Find2()
        {
            Expression<Func<int, int, int>> exp1 = (a, b) => a + b * 2;
            ParameterExpression pexp1 = Expression.Parameter(typeof(int), "a");//参数表达式a
            ParameterExpression pexp2 = Expression.Parameter(typeof(int), "b");//参数表达式b

            ConstantExpression cexp = Expression.Constant(2);//常量表达式2

            BinaryExpression mutExp = Expression.Multiply(pexp2, cexp);//参数表达式b和常量表达式2相乘的表达式
            BinaryExpression addExp = Expression.Add(pexp1, mutExp);//参数表达式1和乘法表达式的求和表达式

            Expression<Func<int, int, int>> lambdaExp = Expression.Lambda<Func<int, int, int>>(addExp, pexp1, pexp2);//将求和表达式转换为lambda表达式
            Console.WriteLine(lambdaExp);
            Func<int, int, int> func = lambdaExp.Compile();
            Console.WriteLine(exp1.Compile()(100, 60));
            Console.WriteLine(func(100, 60));
        }

        /// <summary>
        /// 该方法没有指定参数将报错
        /// </summary>
        public void Find3()
        {
            //BinaryExpression exp1 = Expression.Equal(ConstantExpression.Constant(1),ConstantExpression.Constant(2));
            Expression<Func<int, bool>> exp1 = v => v == 2;

            BinaryExpression exp2 = Expression.And(exp1.Body, ConstantExpression.Constant(true));//没有将exp1转换为调用表达式将报错
            Expression<Func<bool>> lamExp = Expression.Lambda<Func<bool>>(exp2);

            Console.WriteLine(lamExp.Compile()());
        }

        /// <summary>
        /// 手动构造一个表达式树
        /// </summary>
        public void Find4()
        {
           
                Expression<Func<Publisher, bool>> exp1 = p => p.PublisherName.EndsWith("出版社");
                Expression<Func<Publisher, bool>> exp2 = p => p.PublisherID >= 6;

                ParameterExpression pexp = ParameterExpression.Parameter(typeof(Publisher), "p");

                InvocationExpression invokerExp1 = Expression.Invoke(exp1, pexp);//将Lambda表达式exp1应用于参数表达式列表,从而创建一个调用表达式invokerExp1
                InvocationExpression invokerExp2 = Expression.Invoke(exp2, pexp);//将Lambda表达式exp2应用于参数表达式列表,从而创建一个调用表达式invokerExp2

                BinaryExpression bexp = Expression.And(invokerExp2, invokerExp2);
                Expression<Func<Publisher, bool>> e = Expression.Lambda<Func<Publisher, bool>>(bexp, pexp);

                Console.WriteLine(e);//输出这个表达式

                var plist = FindList<Publisher>(e.Compile());
                foreach (var item in plist)
                {
                    Console.WriteLine(item.PublisherID+"\t"+item.PublisherName);
                }
            
        }


        /// <summary>
        /// 使用PredicateExtensions类提供的扩展方法And构造表达式树
        /// </summary>
        public void Find5()
        {
            Expression<Func<Publisher, bool>> exp = p => p.PublisherName.Contains("大学");
            exp = exp.And<Publisher>(p => p.PublisherID >= 6);
            
            Console.WriteLine(exp);

            var plist = FindList<Publisher>(exp.Compile());
            foreach (var item in plist)
            {
                Console.WriteLine(item.PublisherID+"\t"+item.PublisherName);
            }            
        }

        /// <summary>
        /// 使用条件、排序、投影
        /// </summary>
        public void Find6()
        {
            var blist = FindList<Book, string, object>(
                b => b.BookID.StartsWith("ISBN"), 
                b => b.BookID, 
                b => new { b.BookID,b.BookTitle,b.Publisher.PublisherName}
            );

            foreach (var item in blist)
            {   
                foreach (var pi in item.GetType().GetProperties())
                {
                    Console.Write(pi.GetValue(item,null)+"\t");
                }
                Console.WriteLine("\n");
            }
        }

        public void Find8()
        {
            var blist = FindList<Book, string, Book>(
                b => b.BookID.StartsWith("ISBN"),
                "Publisher",
                b => b.BookID,
                b => new Book{ BookID=b.BookID, BookTitle=b.BookTitle, Publisher=new Publisher{PublisherID=b.PublisherID,PublisherName=b.Publisher.PublisherName} }
            );
            foreach (var item in blist)
            {

                Console.WriteLine(item.BookID+"\t"+item.BookTitle+"\t"+item.Publisher.PublisherName);
                Console.WriteLine("\n");
            }
        }

        /// <summary>
        /// 不使用表达式树,传入多个条件表达式实现查询
        /// </summary>
        public void Find7()
        {
            var blist = FindList<Book>(
                            b=>b.BookTitle.Contains("设计"),
                            b=>b.BookPrice<=180                        
                        );

            foreach (var item in blist)
            {
                Console.WriteLine(item.BookID+"\t"+item.BookTitle);
            }
        }

        /// <summary>
        /// 保存书籍
        /// </summary>
        public void Post1()
        {
            base.AddObject(new Book { BookID = "ISBN0006",BookTitle="C++Primer", BookDate=DateTime.Now,BookPrice=98,PublisherID=11 });
            base.AddObject(new Book { BookID = "ISBN0007", BookTitle = "C++大学教程", BookDate = DateTime.Now.AddYears(-1), BookPrice = 78, PublisherID = 11 });
            base.AddObject(new Book { BookID = "ISBN0008", BookTitle = "C和指针", BookDate = DateTime.Now.AddMonths(-7), BookPrice = 88, PublisherID = 11 });

            base.Commit();
        }

       
        
    }
}
 
 
代码未经过整理,比较凌乱,由于方法甚至没有使用DaoTemplate的集成微笑
 
 

你可能感兴趣的:(Entity Framework 三层架构--持久层使用封装之实现类DaoTemplate)