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

anzhiqiang_touzi 2011-12-22 11:07:07
快新年了:先祝大家新年好。很久没征求大家的意见了。现在想征求大家的意义和设计思路。
最近在研究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的速度
请大家帮我想想如何提高表达式的编译速度。
...全文
255 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
香儿爱土豆 2011-12-31
  • 打赏
  • 举报
回复
没有什么好的~最方便的,最简单的,就是好的~没必要过多纠结于ORM吧,.NET非Java,什么Spring之类的~

.NET4.0之后,你会发现C#越来越爽了,nice~
anzhiqiang_touzi 2011-12-23
  • 打赏
  • 举报
回复
那現在用什麼ORM比較好呢?
vrhero 2011-12-23
  • 打赏
  • 举报
回复
这款老牛早已被淘汰了,没必要在这种过时的过渡产品上浪费任何时间...
Entity Developer是一个强大的ORM设计器,支持 ADO.NET Entity Framework, NHibernate, LinqConnect 和 LINQ to SQL。你可以使用模型首先和数据首先的方法设计ORM模型并生成C#或者Visual Basic .NET代码。它引入了新的方法设计ORM模型,提高开发效率,简化数据库应用的开发。 可视化ORM模型设计器并支持代码生成 Entity Developer允许你可视化创建和编辑NHibernate,Entity Framework,LinqConnect 和 LINQ to SQL模型,无需一行XML代码。它支持创建各种一映射,如表分割,映射实体到多个表,复杂类型,继承分层,从Sel ect语句创建实体,从SQL代码创建方法等。由于使用了类似T4的模板,所以代码生成非常灵活,另外你还能创建自己的模板用于其他的编程语言。 多ORM支持 Entity Developer 支持 NHibernate, Entity Framework,LinqConnect 和 LINQ to SQL模型。 强大的代码生成 Entity Developer提供基于T4类似的模板生成代码框架,针对不同使用情况提供大量预定义的模板,模板化生成上下文,实体,映射,支持流,属性和XML映射,包括持久层感知和持久层无感知实体,支持验证框架等。另外模板提供自动生成MVC Controller和视图的功能。Data Transfer Object 提供转换器类和Data Annotations metadata类。 适用于各种.NET ORM的可视设计器 Entity Developer可以帮助您在一个统一的界面中为各种.NET ORM设计模型。您可以在一个工具中获得对所有ORM的支持,或者您可以购买单独的版本,与其中一个受支持的ORM一起使用。 支持EntityFramework和EF Core 对于Entity Framework v1-v6以及最新的EF Core2.2,我们的设计器提供了比EDM设计器更多的设计和代码生成功能。 Entity框架核心 设计实体框架核心模型可视化。通过大量设置获得模型优先和数据库优先支持。 NHibernate 直观地编辑NHibernate模型,为NHibernate 3或4生成XML,流畅或Loquacious映射和配置。 LINQ to SQL 直观地设计LINQ to SQL模型。 获得更好的模型优先和数据库优先支持,并轻松将模型更改应用于数据库。 LinqConnect 积极支持Devart的LINQ to SQL兼容ORM以及更多功能,Entity Developer作为其ORM设计器。 Telerik数据访问 可视化设计最新Telerik数据访问版本的模型,并通过Fluent Mapping API生成仅代码映射。 功能丰富的设计器,具有强大的代码生成功能 无缝Visual Studio集成 支持Model-First和Database-First 可视化创建几乎所有类型的映射 将模型更改应用于数据库,反之亦然 强大的模型重构 优化大型模型的工作 设计LINQ / ESQL / HQL查询执行 查看和编辑源表中的数据 背景模型验证 基于T4模板的代码生成 大量预定义模板 生成C#或VB代码 每个类的文件,部分类生成 自定义属性支持 自定义模板支持 带语法高亮的模板编辑器 高质量的生成代码 高度可定制的一代

8,497

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧