直达通超过实际体自动映射数据库进行询问万博manbetx客户端

   
这里有八个至关心器重要词:轻量级实体类数据容器,还会有贰个私人民居房的关键词:通用。那多少个名词之间有如何关联吗?

写了一个数据库操作类,达到通超过实际体自动映射数据库进行询问,增添,删除,修改操作,啥也不说了,直接上代码:

   
一般的话,操作实体类往往伴随着贰个实体类会集,而那么些聚焦就是实体类的容器,在此处本人将“容器”视作二个比集结越来越宽广的概念,比方Entity
Framework做了二个重量级的容器ObjectContext,用于与作为靶子(这么些指标为
EDM 中定义的实业类型的实例)的多寡实行交互。

反回多少个实体,通过枚举参数鲜明使用质量/天性开展字段映射(转款做表和主键映射)

   
实体类与容器未有早晚关系,比方DataSet也是三个容器,它存款和储蓄并操作DataTable,而DataTable也得以用作是逐条单元格数据的容器…

万博manbetx客户端 1万博manbetx客户端 2Code
/// <summary>
        /// 获取单个实体
        /// </summary>
        /// <typeparam name=”TEntity”>实体(泛型)</typeparam>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”exeEntityType”>按属性/性情映射</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>实体</returns>
        public static TEntity GetEntity<TEntity>(string cmdText, CommandType commandType,AppEnum.ExeEntityType exeEntityType,params DbParameter[] paramers) where TEntity:new()
        {
            TEntity entity = new TEntity();
            using (IDataReader reader = DbHelper.CreateDataReader(cmdText, commandType, paramers))
            {
                if (reader.Read())
                {
                    Type entityType = entity.GetType();
                    PropertyInfo[] propertyInfos=entityType.GetProperties();
                    foreach(PropertyInfo property in propertyInfos)
                    {
                        if (exeEntityType == AppEnum.ExeEntityType.isAttribute)
                        {
                            DataFieldAttribute datafieldAttribute = GetDataFieldAttribute(property);
                            if (datafieldAttribute == null)
                                throw new AssionException(“AppEnum.ExeEntityType枚举为 isAttribute 时,实体类供给内定特性!”);
                            if (!(reader[datafieldAttribute.FieldName] is DBNull))
                                property.SetValue(entity, reader[datafieldAttribute.FieldName], null);
                        }
                        else if (exeEntityType == AppEnum.ExeEntityType.isProperty)
                        {
                            if (!(reader[property.Name] is DBNull))
                                property.SetValue(entity, reader[property.Name], null);
                        }
                    }
                }
                reader.Close();
                reader.Dispose();
            }
            return entity;
        }

   
不过,那么些“数据容器”依旧呈现相当的重量级,里面有太多要相互的子对象,为此作者在PDF.NET(PWMIS数据开荒框架)中定义了二个可怜轻量级的实业数据容器,它存款和储蓄数据的尺度很简短,就是多个object[][],外加一个相应的字段名称数组,另外诸如表的成分据等消息都未曾存款和储蓄,也便是下边程序中的3个个体对象:

回到一个实体集结,类似上面的

 

万博manbetx客户端 3万博manbetx客户端 4Code
/// <summary>
        /// 获取实体群集
        /// </summary>
        /// <typeparam name=”TEntity”>实体(泛型)</typeparam>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”exeEntityType”>按属性/本性映射</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>实体会集</returns>
        public static IList<TEntity> GetEntityList<TEntity>(string cmdText, CommandType commandType, AppEnum.ExeEntityType exeEntityType, params DbParameter[] paramers) where TEntity : new()
        {
            IList<TEntity> entityList = new List<TEntity>();
            using (IDataReader reader = DbHelper.CreateDataReader(cmdText, commandType, paramers))
            {
                while (reader.Read())
                {
                    TEntity entity = new TEntity();
                    Type entityType = entity.GetType();
                    PropertyInfo[] propertyInfos = entityType.GetProperties();
                    foreach (PropertyInfo property in propertyInfos)
                    {
                        if (exeEntityType == AppEnum.ExeEntityType.isAttribute)
                        {
                            DataFieldAttribute datafieldAttribute = GetDataFieldAttribute(property);
                            if (datafieldAttribute == null)
                                throw new AssionException(“AppEnum.ExeEntityType枚举为 isAttribute 时,实体类须求钦命天性!”);
                            if (!(reader[datafieldAttribute.FieldName] is DBNull))
                                property.SetValue(entity, reader[datafieldAttribute.FieldName], null);
                        }
                        else if (exeEntityType == AppEnum.ExeEntityType.isProperty)
                        {
                            if (!(reader[property.Name] is DBNull))
                                property.SetValue(entity, reader[property.Name], null);
                        }                        
                    }
                    entityList.Add(entity);
                }
            }
            return entityList;
        }

    /// <summary>
    /// 实体数据容器
    /// </summary>
    public class EntityContainer
    {
        private string[] fieldNames;
        private List<object[]> Values;
        private object[] currValue;

实施SQL实体映射操作,能够写INSERT、UPDATE、DELETE
操作,那样灵活些,抽时间再产生个自动映射生成SQL的,可是灵活性就差些了

    }

万博manbetx客户端 5万博manbetx客户端 6Code
 /// <summary>
        /// 插入,更新,删除数据库实体
        /// </summary>
        /// <typeparam name=”TEntity”>实体(泛型)</typeparam>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”exeEntityType”>按属性/特性映射</param>
        /// <param name=”entity”>实体</param>
        /// <returns>影响行数</returns>
        public static int ExeEntity<TEntity>(string cmdText, CommandType commandType, AppEnum.ExeEntityType exeEntityType,TEntity entity) where TEntity : new()
        {
            Type entityType = entity.GetType();
            PropertyInfo[] propertyInfos = entityType.GetProperties();
            List<DbParameter> paramerList = new List<DbParameter>();
            foreach (PropertyInfo property in propertyInfos)
            {
                if (exeEntityType == AppEnum.ExeEntityType.isAttribute)
                {
                    DataFieldAttribute datafieldAttribute = GetDataFieldAttribute(property);
                    if (datafieldAttribute == null)
                        throw new AssionException(“AppEnum.ExeEntityType枚举为 isAttribute 时,实体类供给钦赐天性!”);
                    object oval=property.GetValue(entity,null);
                    oval = oval == null ? DBNull.Value : oval;
                    paramerList.Add(DbHelper.CreateParamer(“@” + datafieldAttribute.FieldName, oval));
                }
                else if (exeEntityType == AppEnum.ExeEntityType.isProperty)
                {
                    object oval = property.GetValue(entity, null);
                    oval = oval == null ? DBNull.Value : oval;
                    paramerList.Add(DbHelper.CreateParamer(“@” + property.Name, oval));
                }
            }
            int retval=DbHelper.ExecuteNonQuery(cmdText, commandType, paramerList.ToArray());

 

            return retval;
        }

实体容器接收贰个DataReader对象,将中间的数量读入Values
数组,上面是应和的艺术代码:

下边是字段的自定义性情和得到本性的代码:

 

万博manbetx客户端 7万博manbetx客户端 8Code
    /// <summary>
    /// 自定义个性:映射数据库字段名
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct|AttributeTargets.Property|AttributeTargets.Field)]
    public class DataFieldAttribute:Attribute
    {
        private string _fieldName; //字段名
        public string FieldName
        {
            get { return _fieldName; }
            set { _fieldName = value; }
        }

        /// <summary>
        /// 实施DataReader查询,并将查询结果缓存
        /// </summary>
        /// <param name=”reader”>数据阅读器</param>
        /// <returns>结果行数</returns>
        public int Execute(IDataReader reader)
        {
            List<object[]> list = new List<object[]>();
            using (reader)
            {
                if (reader.Read())
                {
                    int fcount = reader.FieldCount;
                    fieldNames = new string[fcount];
                    object[] values = null;

        public DataFieldAttribute(string fieldName)
        {
            this._fieldName = fieldName;
        }
    }

                    for (int i = 0; i < fcount; i++)
                        fieldNames[i] = reader.GetName(i);

/// <summary>
        /// 获取DataFieldAttribute特性
        /// </summary>
        /// <param name=”property”>属性</param>
        /// <returns>DataFieldAttribute</returns>
        private static DataFieldAttribute GetDataFieldAttribute(PropertyInfo property)
        {
            object[] oArr=property.GetCustomAttributes(true);
            for(int i=0;i<oArr.Length;i++)
            {
                if(oArr[i] is DataFieldAttribute)
                    return (DataFieldAttribute)oArr[i];
            }
            return null;
        }

                    do
                    {
                        values = new object[fcount];
                        reader.GetValues(values);
                        list.Add(values);
                    } while (reader.Read());

接纳示例:
率先实体加上性情:

                }
            }
            this.Values = list;
            return list.Count;
        }

万博manbetx客户端 9万博manbetx客户端 10Code
    public class People
    {
        [PrimaryKey()]
        [DataField(“DbName”)]
        public string Name { get; set; }
        [DataField(“DbTel”)]
        public string tel { get; set; }
    }

次第中运用 reader.GetValues(values)
方法,它不用对每列进行多少读取,所以数据读取的频率较高。

调用代码:
获得五个实体集结:

后天数量寄存进去了,怎么样使用啊?为了产生通用,具体每一个数据的应用照旧交给使用者自身去处理啊,所以选择一个寄托方法来管理:

 IList<People> peopleList = ExecuteEntity.GetEntityList<People>(“SELECT DbName,DbTel FROM Test”, CommandType.Text, AppEnum.ExeEntityType.isAttribute, null);

 

向数据库插入实体数据:

        /// <summary>
        /// 选取自定义的映射格局,将数据容器中的数据映射到钦命的类中 
        /// </summary>
        /// <typeparam name=”TResult”>结果类型</typeparam>
        /// <param name=”fun”>管理多少的点子</param>
        /// <returns></returns>
        public IEnumerable<TResult> Map<TResult>(Func<TResult> fun) where TResult : class, new()
        {
            if (this.Values != null && this.fieldNames != null)
            {
                foreach (object[] itemValues in this.Values)
                {
                    TResult t = new TResult();
                    this.currValue = itemValues;
                    fun(t);
                    yield return t;
                }
            }
            else
            {
                throw new Exception(“EntityContainer 错误,调用该方法前请先调用Execute 方法。”);
            }
        }

ExecuteEntity.ExeEntity<People>(“INSERT INTO Test (DbName,DbTel) VALUES (@DbName,@DbTel)”, CommandType.Text, AppEnum.ExeEntityType.isAttribute, people);

上边是该方式的采纳示例:

谈到底再黏附几个基础的数据库操作类:

 

万博manbetx客户端 11万博manbetx客户端 12Code
/// <summary>
    /// 通用数据库扶助类
    /// </summary>
    public static class DbHelper
    {
        #region 连接配置读取

           
EntityContainer ec = new EntityContainer(q, db);
            ec.Execute();
            var mapUser2= ec.Map<User>((e) => 
            {
                e.Age = ec.GetItemValue<int>(“Age”);
                e.ID = ec.GetItemValue<int>(“ID”);
                e.Name = ec.GetItemValue<string>(“name”);//不区分轻重缓急写
                return e; 
            }
            ).ToList ();

        /// <summary>
        /// 数据库类型
        /// </summary>
        private static readonly string dataProvider = ConfigurationManager.ConnectionStrings[“ConnectionString”].ProviderName;

 除了足以使用 GetItemValue<T>(string 田野(field)Name)
方法来收获迭代的此时此刻行的某列数据外,也足以利用 GetItemValue<T>(int
田野(field)Index) 方法。

        /// <summary>
        /// 反射数据库类型
        /// </summary>
        private static readonly DbProviderFactory dataFactory = DbProviderFactories.GetFactory(dataProvider);

除此以外,还提供了贰个将数据映射到PDF.NET实体类的办法,下边是措施的概念:

        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        private static readonly string connectionString = ConfigurationManager.ConnectionStrings[“ConnectionString”].ConnectionString;

 

        #endregion

        /// <summary>
        /// 将数据从容器中映射到实体中
        /// </summary>
        /// <typeparam name=”T”></typeparam>
        /// <returns></returns>
        public IEnumerable<T> Map<T>() where T : EntityBase{

        #region 连接命令

             //具体代码略

        /// <summary>
        /// 创造连接
        /// </summary>
        /// <returns>dbconnection</returns>
        public static DbConnection CreateConnection()
        {
            DbConnection dbConn = dataFactory.CreateConnection();
            dbConn.ConnectionString = connectionString;
            return dbConn;
        }

        }

        /// <summary>
        /// 创设命令
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>command</returns>
        public static DbCommand CreateCommand(string cmdText,CommandType commandType,params DbParameter[] paramers)
        {
            DbConnection dbConn=CreateConnection();
            dbConn.Open();
            DbCommand dbCmd = dataFactory.CreateCommand();
            dbCmd.Connection = dbConn;
            dbCmd.CommandText = cmdText;
            dbCmd.CommandType = commandType;
            if(paramers!=null)
                dbCmd.Parameters.AddRange(paramers);

地点的测量检验例子中,User类是叁个实体类,所以能够用上边包车型大巴诀窍一贯获得该类的实例对象集合:

            return dbCmd;
        }

 

        #endregion

           
EntityContainer ec = new EntityContainer(q, db);
            ec.Execute();
            var mapUser1 = ec.Map<User>().ToList ();

        #region 数据实行措施

在Map方法中,能够映射出狂妄PDF.NET实体类,大概另外自定义的POCO实体类,并且未有映射次数限制。看到这里聪明的您或者要问了,上边的例证能够映射User之外的实体吗?答案是截然能够!

        /// <summary>
        /// 创设带参数的只读器
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>reader</returns>
        public static DbDataReader CreateDataReader(string cmdText, CommandType commandType, params DbParameter[] paramers)
        {
            DbDataReader reader = null;
            reader = CreateCommand(cmdText, commandType, paramers).ExecuteReader(CommandBehavior.CloseConnection);
            return reader;
        }

先看二个例证,大家假若系统中还设有一个实体类
Group,我们采纳PDF.NET的OQL表明式写一个援救三个实体连接查询的说话:

        /// <summary>
        /// 创建无参数的只读器
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <returns>reader</returns>
        public static DbDataReader CreateDataReader(string cmdText, CommandType commandType)
        {
            DbDataReader reader = null;
            reader = CreateCommand(cmdText, commandType, null).ExecuteReader(CommandBehavior.CloseConnection);           
            return reader;
        }

 

        /// <summary>
        /// 试行二个带参数的SQL/存款和储蓄进度
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>影响行数</returns>
        public static int ExecuteNonQuery(string cmdText, CommandType commandType, params DbParameter[] paramers)
        {
            int retval = CreateCommand(cmdText, commandType, paramers).ExecuteNonQuery();
            return retval;
        }

OQL q=OQL.From(user)
         .InnerJoin(group) //连接Group实体
         .On(user.GroupID,group.ID)
         .Select(user.ID,user.Name,group.GroupName) //采纳内定的字段

        /// <summary>
        /// 施行两个不带参数的SQL/存款和储蓄过程
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <returns>影响行数</returns>
        public static int ExecuteNonQuery(string cmdText, CommandType commandType)
        {
            int retval = CreateCommand(cmdText, commandType, null).ExecuteNonQuery();
            return retval;
        }

下边就足以映射出两个实体集合了:

        /// <summary>
        /// 施行二个带参数的SQL/存款和储蓄进程有作业的
        /// </summary>
        /// <param name=”tran”>事务</param>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commmandType”>命令类型</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>影响行数</returns>
        public static int ExecuteNonQuery(DbTransaction tran,string cmdText,CommandType commmandType,params DbParameter[] paramers)
        {
            DbConnection dbConn = tran.Connection;
            DbCommand dbCmd=dataFactory.CreateCommand();
            dbCmd.Connection=dbConn;
            dbCmd.CommandType=commmandType;
            dbCmd.CommandText=cmdText;
            dbCmd.Parameters.AddRange(paramers);
            dbCmd.Transaction = tran;
            int retval=dbCmd.ExecuteNonQuery();
            return retval;
        }

 

        /// <summary>
        /// 试行贰个无参数的SQL/存款和储蓄进程有业务的
        /// </summary>
        /// <param name=”tran”>事务</param>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commmandType”>命令类型</param>
        /// <returns>影响行数</returns>
        public static int ExecuteNonQuery(DbTransaction tran, string cmdText, CommandType commmandType)
        {
            DbConnection dbConn = tran.Connection;
            DbCommand dbCmd = dataFactory.CreateCommand();
            dbCmd.Connection = dbConn;
            dbCmd.CommandType = commmandType;
            dbCmd.CommandText = cmdText;
            dbCmd.Transaction = tran;
            int retval = dbCmd.ExecuteNonQuery();
            return retval;
        }

           
EntityContainer ec = new EntityContainer(q, db);
            ec.Execute(); //能够归纳此行调用
            var mapUser1 = ec.Map<User>().ToList ();
            var mapGroup1=
ec.Map<Group>().ToList();

        /// <summary>
        /// 推行贰个带参数的SQL/存款和储蓄进程重临首行首列
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>值</returns>
        public static object ExecuteScalar(string cmdText, CommandType commandType, params DbParameter[] paramers)
        {
            object retval = CreateCommand(cmdText,commandType,paramers).ExecuteScalar();
            return retval;
        }

一经感到那样分别选用多少个实体对象会集(
user和group)相比费心,那么再自定义三个“顾客单位”类就能够:

        /// <summary>
        /// 实践一个无参数的SQL/存款和储蓄进程重回首行首列
        /// </summary>
        /// <param name=”cmdText”>命令</param>
        /// <param name=”commandType”>命令类型</param>
        /// <param name=”paramers”>参数数组</param>
        /// <returns>值</returns>
        public static object ExecuteScalar(string cmdText, CommandType commandType)
        {
            object retval = CreateCommand(cmdText,commandType,null).ExecuteScalar();
            return retval;
        }

 

        #endregion

 class UserGroup 
{
    int ID{get;set;}
    string Name{get;set;}
    string GroupName{get;set;}
}

        #region 成立参数方法
        /// <summary>
        /// 创立参数
        /// </summary>
        /// <param name=”pName”>参数名</param>
        /// <param name=”pValue”>参数值</param>
        /// <returns>参数</returns>
        public static DbParameter CreateParamer(string pName, object pValue)
        {
            DbParameter paramer = dataFactory.CreateParameter();
            paramer.ParameterName = pName;
            paramer.Value = pValue;
            return paramer;
        }

从此,能够像上边那样来选拔数据:

        /// <summary>
        /// 创制参数
        /// </summary>
        /// <param name=”pName”>参数名</param>
        /// <param name=”pValue”>参数值</param>
        /// <param name=”pType”>参数类型</param>
        /// <returns>参数</returns>
        public static DbParameter CreateParamer(string pName, object pValue, DbType pType)
        {
            DbParameter paramer = dataFactory.CreateParameter();
            paramer.ParameterName = pName;
            paramer.Value = pValue;
            paramer.DbType = pType;
            return paramer;
        }

 

        /// <summary>
        /// 创制参数
        /// </summary>
        /// <param name=”pName”>参数名</param>
        /// <param name=”pValue”>参数值</param>
        /// <param name=”pType”>参数类型</param>
        /// <param name=”pSize”>长度</param>
        /// <returns>参数</returns>
        public static DbParameter CreateParamer(string pName, object pValue, DbType pType, int pSize)
        {
            DbParameter paramer = dataFactory.CreateParameter();
            paramer.ParameterName = pName;
            paramer.Value = pValue;
            paramer.DbType = pType;
            paramer.Size = pSize;
            return paramer;
        }

            EntityContainer ec = new EntityContainer(q, db);
            //ec.Execute();//能够回顾此行调用

        #endregion
    }

            var mapEntity= ec.Map<UserGroup>((e) => 
            {
                e.GroupName = ec.GetItemValue<int>(“GroupName”);
                e.ID = ec.GetItemValue<int>(“ID”);
                e.Name = ec.GetItemValue<string>(“name”);//不区分轻重缓急写
/*
//也许选拔索引的方法,但不能够不旗帜显著地方OQL表明式Select方法里面属性的逐条 
                e.GroupName = ec.GetItemValue<strng>(2);
                e.ID = ec.GetItemValue<int>(0);
                e.Name = ec.GetItemValue<string>(1);

有时就实现了这样多,继续支付,感到贰个庞大的数据库操作类正是要大,要多,要全,要爆力!

*/
                return e; 
            }
            ).ToList ();

  

地点的写法未有LINQ那么完美,人家LINQ是近水楼台先得月,MS自家的抽芽,能够注重“编写翻译器语法糖”来写出卓越的LINQ程序,但咱们的那几个实现从规律上说比较轻快,在无数地下的ORM框架中,真正帮忙了实体类的多表连接查询!

 

有关OQL的多实体连接查询仅在PDF.NET框架V4.1现在版本补助,该功用作为框架的一项主要效能扩充,已经在商业贸易类型中初露利用,感兴趣的朋友能够一并探讨。

上面包车型客车代码是实在项目中的一段代码,我们来拜会完整的调用格局:

 

public string GetTradeTypeID(string foundAccount,string jjdm,string type)
        {
            /*施行上边包车型地铁查询将选拔如下类似的SQL:
             select distinct a.tradetype tradetypeid from wft_customerfundtrade a
                 left join wft_customerfundtradedetails b on a.tradetype =b.tradetypeid
                      where   (a.fundaccount =’1185919705′  and a.jjdm =’KF0003’)
                         and ( b.tradetype=’定投’ or b.tradetype=’基金转变的记帐’)
             * 
             */
            WFT_CustomerFundTrade trade = new WFT_CustomerFundTrade() { FundAccount = foundAccount, JJDM = jjdm };
            WFT_CustomerFundTradeDetails detail = new WFT_CustomerFundTradeDetails() { TradeType = type };
            OQLCompare cmpAll = new OQLCompare(trade, detail);

            OQL q = OQL.From(trade)
                .LeftJoin(detail).On(trade.TradeType, detail.TradeTypeId)
                .Select(trade.TradeType)
                .Where(
                        (cmpAll.Comparer(trade.FundAccount) & cmpAll.Comparer(trade.JJDM)) &
                        (cmpAll.Comparer(detail.TradeType) | cmpAll.Comparer(detail.TradeType, “=”, “基金转变的记帐”))
                )
                .END;

            q.Distinct = true;

            EntityContainer container = new EntityContainer(q);
            var result = container.Map<WFT_CustomerFundTrade>().ToList();
            if (result.Count == 0)
                return “”;
            else
                return result[0].TradeType;
}

由那个例子能够看看,PDF.NET的ORM框架中的实体对象查询语言–OQL,已经得以做到很复杂的询问了,满含多实体类关联合检查询。