首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

关于Linq To Sql的效率和设计的有关问题<<ORM>>

2012-12-16 
关于Linq To Sql的效率和设计的问题ORM本帖最后由 anzhiqiang_touzi 于 2011-12-22 23:38:56 编辑快新

关于Linq To Sql的效率和设计的问题<<ORM>>
本帖最后由 anzhiqiang_touzi 于 2011-12-22 23:38:56 编辑 快新年了:先祝大家新年好。很久没征求大家的意见了。现在想征求大家的意义和设计思路。
    最近在研究ORM架构。看了很多ORM架构。都不是很满意。不是配置复杂就是速度慢得像老牛样。
但是我还是选择了一款"老牛":Linq To SQL
先说说我的设计思路:改进Linq To SQL原始的:增加,修改,删除,提高效率

官方提供的
新增方式:


  DataClasses1DataContext ct = new DataClasses1DataContext();
        for (int i = 0; i < 10000; i++)
        {
            Common_Gen m = new Common_Gen();
            m.GenId = 1;
            m.GenType = "Type";
            m.Memo = "Memo";
            m.UpdateDate = DateTime.Now; 
            ct.Common_Gen.InsertOnSubmit(m);
        }
        ct.SubmitChanges();

修改时:官方需要从DataContext中抓去一个对象然后更新。这样不用说,相率当然有问题了。

效率问题:DataClasses1DataContext 采用对象跟踪问题
批量提交大数据量会越来越慢,到最后一条数据便得最慢
ct.SubmitChanges();最后才轮到它提交.如果不用对象跟踪的话是不能提交的会有异常出现
坚决办法:改进方法
 /// <summary>
        /// 新增数据
        /// </summary>
        /// <typeparam name="TEntity">实体</typeparam>
        /// <param name="table">Table</param>
        /// <returns>n</returns>
        public static int Add<TEntity>(this Table<TEntity> table, TEntity entity) where TEntity : class
        {
            DbCommand cmd = table.Context.Connection.CreateCommand();
            Type entityType = typeof(TEntity);
            var metaTable = table.Context.Mapping.GetTable(entityType);
            ReadOnlyCollection<MetaDataMember> dataMembers = metaTable.RowType.DataMembers;
            List<object> values = new List<object>();
            //自动增长列
            string IsDbGeneratedColumnName = null;
            StringBuilder sbColumnNames = new StringBuilder();
            StringBuilder sbValues = new StringBuilder();

            foreach (MetaDataMember mm in dataMembers)
            {
                if (!mm.IsDbGenerated && mm.DbType != null)


                {
                    sbColumnNames.Append("[" + mm.Name + "],");
                    sbValues.Append("@" + mm.Name + ",");
                    DbParameter ps = cmd.CreateParameter();
                    ps.ParameterName = mm.Name;
                    ps.Value = entityType.GetProperty(mm.Name).GetValue(entity, null);
                    cmd.Parameters.Add(ps);
                }
                if (mm.IsDbGenerated && mm.IsPrimaryKey)
                {
                    IsDbGeneratedColumnName = mm.Name;
                }
            }
            sbColumnNames.Remove(sbColumnNames.Length - 1, 1);
            sbValues.Remove(sbValues.Length - 1, 1);
            var tableName = "[" + metaTable.TableName + "]";
            if (cmd.Connection.State != ConnectionState.Open)
            {
                cmd.Connection.Open();
            }
            string CommandText = "";
            if (IsDbGeneratedColumnName == null)
            {
                CommandText = "INSERT INTO " + tableName + "(" + sbColumnNames + ") VALUES(" + sbValues + "); ";
                cmd.CommandText = CommandText;
                cmd.Transaction = table.Context.Transaction;
                int n = cmd.ExecuteNonQuery();
                return n;
            }
            else


            {
                CommandText = "INSERT INTO " + tableName + "(" + sbColumnNames + ") VALUES(" + sbValues + "); SELECT CONVERT(int,SCOPE_IDENTITY()) AS [value]";
                cmd.CommandText = CommandText;
                cmd.Transaction = table.Context.Transaction;
                object n = cmd.ExecuteScalar();
                entityType.GetProperty(IsDbGeneratedColumnName).SetValue(entity, n, null);
                return 1;
            }
        }



//数据访问基类:采用直接提交方式,关闭DataContext对象跟踪
public class TemplateDao<T> : ITemplateDao<T> where T : class
    {
        public DataContext DataContext { get; set; }

        /// <summary>
        /// 增加实体
        /// </summary> 
        public virtual void Add(T model)
        {
            Table<T> table = this.DataContext.GetTable<T>();
            table.Add(model);
        }
    
       /// <summary>
        /// 单表删除数据
        /// </summary>
        /// <param name="expression">Expression表达式</param>
        /// <returns>影响的行数</returns>
        public virtual int Delete(Expression<Func<T, bool>> expression)
        {
            Table<T> table = this.DataContext.GetTable<T>();
            return table.Delete(expression);
        }

       /// <summary>
        /// 单表更新数据
        /// </summary>
        /// <param name="model">实体</param> 
        public virtual int Update(T model)
        {
            Table<T> table = this.LoadAll();
            return table.Update(model);


        }

        /// <summary>
        /// 单表更新数据
        /// </summary>
        /// <param name="expression">条件表达式</param>
        /// <param name="updater">更新表达式</param>
        /// <returns></returns>
        public virtual int UpdateWhere(Expression<Func<T, bool>> expression, Expression<Func<T, T>> updater)
        {
            Table<T> table = this.LoadAll();
            return table.UpdateWhere(expression, updater);
        }
}


说说我设计时的想法:

更新:通过我改进的代码来看:有朋友可能会有疑问:UpdateWhere 与 Update两个方法有个是多余的。
UpdateWhere(Expression<Func<T, bool>> expression, Expression<Func<T, T>> updater)
表达式:慢。为啥呢:Expression是需要动态分析和编译的。然后取得数据。大家想想有什么办法可以把速度提起来吗?我没想到。但是这方法有优势:可以更新某个对象的部分字段,而且条件也可以动态的。
Update(T model):更新全部字段。但是速度快。
删除:还没想到有什么方式替换表达式,但是至少需要改进的地方是:避开DataContext操作,自己处理
  /// <summary>
        /// 单表删除数据
        /// </summary> 
        public static int Delete<TEntity>(this Table<TEntity> table, Expression<Func<TEntity, bool>> filter) where TEntity : class
        {
            DbCommand cmd = table.Context.Connection.CreateCommand();
            //获取表名
            string tableName = table.Context.Mapping.GetTable(typeof(TEntity)).TableName;
            //查询条件表达式转换成SQL的条件语句
            ConditionBuilder builder = new ConditionBuilder();
            builder.Build(filter.Body);
            string sqlCondition = builder.Condition;

            //SQL命令
            string commandText = string.Format("DELETE FROM {0} WHERE {1}", tableName, sqlCondition);
            cmd.CommandText = commandText;
            //获取SQL参数数组 
            List<KeyValuePair<string, object>> args = builder.Arguments;
            foreach (KeyValuePair<string, object> arg in args)
            {
                DbParameter ps = cmd.CreateParameter();


                ps.ParameterName = arg.Key;
                ps.Value = arg.Value;
                cmd.Parameters.Add(ps);
            }
            if (table.Context.Connection.State != ConnectionState.Open)
            {
                table.Context.Connection.Open();
            }
            if (table.Context.Transaction != null)
            {
                cmd.Transaction = table.Context.Transaction;
            }
            return cmd.ExecuteNonQuery();
        }



问题点:为什么不用:table.Context.ExecuteCommand(comand, parameters);
我测试过:好像这个也是慢了点点


个人认为:Linq To SQL的查询不需要改进,Linq To Sql 查询做的很不错的。如果大家觉得查询慢的话。
我是这样认为的:查询速度的提升是在于:数据库的优化,SQL语句的优化(注意自己的Linq写法),PC机的配置等等
如果单单说解析与数据库优化的话:可以忽略的。

另外:
1.将我们写好的扩展抽象出来做个类似NH的ITemplateDao的接口。TemplateDao做基础类
2.然后写一个AOP架构我们的Business业务逻辑控制我们的DataContext.目地:处理事务机制,日志处理
3.在调用我们的业务逻辑的时候注入我们的DataContext,在方法调用完毕的时候,回收DataContex并且提交事务
4.注:每个Dao对象需要动态的注入。然后个每个Dao注入DataContext
经测试结果:比较操作30000条数据
                                       1.Ado.net             2.Linq                3.EnterpriseLibrary        4.Linq是否使用表达式
增加耗时:     4.5152583秒         5.8073322秒          13.5097727秒              否
修改耗时:     4.6222644秒         5.4363109秒          18.3780511秒              否
删除耗时:     3.5042004秒         17.2679877秒         6.3913656秒               是
查询耗时:    未测试

问题点:Linq表达式速度没办法提起来,向大家请教如何提高Expression的动态编译。
在网找了个编译缓存的代码,但是还是慢,我的目标是:使用表达式争取接近:Enterprise Library的速度
请大家帮我想想如何提高表达式的编译速度。
[解决办法]
这款老牛早已被淘汰了,没必要在这种过时的过渡产品上浪费任何时间...
[解决办法]
那現在用什麼ORM比較好呢?
[解决办法]
没有什么好的~最方便的,最简单的,就是好的~没必要过多纠结于ORM吧,.NET非Java,什么Spring之类的~

.NET4.0之后,你会发现C#越来越爽了,nice~

热点排行