/// 获取单个实体

   
这里有七个举足轻重词:轻量级实体类多少容器,还有一个机密的显要词:通用。这么些名词之间有什么联系呢?

写了一个数据库操作类,达到通过实体自动映射数据库举办查询,添加,删除,修改操作,啥也不说了,直接上代码:

   
一般的话,操作实体类往往伴随着一个实体类集合,而这个聚集就是实体类的器皿,在此处自己将“容器”视作一个比集合更宽广的定义,例如Entity
Framework做了一个重量级的器皿ObjectContext,用于与作为对象(那多少个目的为
EDM 中定义的实体类型的实例)的多寡开展互动。

反回一个实体,通过枚举参数确定使用性质/特性开展字段映射(转款做表和主键映射)

   
实体类与容器没有必然涉及,例如DataSet也是一个容器,它存储并操作DataTable,而DataTable也足以看作是逐一单元格数据的容器…

图片 1图片 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个村办对象:

回到一个实体集合,类似上边的

 

图片 3图片 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的,然而灵活性就差些了

    }

图片 5图片 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
数组,上面是对应的不二法门代码:

上面是字段的自定义特性和得到特性的代码:

 

图片 7图片 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;
        }

图片 9图片 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);

下边是该方法的应用示例:

末尾再黏附一个基础的数据库操作类:

 

图片 11图片 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 fieldName)
方法来博取迭代的近日行的某列数据外,也得以拔取 GetItemValue<T>(int
fieldIndex) 方法。

        /// <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,已经可以完成很复杂的查询了,包括多实体类关联查询。