【问题标题】:Reflection to generate SQL in C#?在 C# 中生成 SQL 的反射?
【发布时间】:2011-09-10 00:48:48
【问题描述】:

我有自己的 ORM,但我注意到当我得到 100k 个结果时它的性能很差。对于每次迭代,我都会反映每种类型、它的字段/属性和它使用的类(1 个深度)。

反映一个类 10 万次会变慢。有什么东西我可以用来生成 C# 代码,所以我不需要使用反射吗?我可以将重要的选择查询重写为常规 sql 而不是使用我的 ORM,但我想我先问是否有工具。

我正在使用 mysql 数据库。

-edit- 临时解决方案。 dapper.net 似乎具有我需要的查询性能,而我自己的 orm 创建表、插入并具有附加执行功能。在两者之间,我认为我拥有我需要的一切。 (请记住,我需要 dapper 提供的选择性能,除非我的网站变得庞大,否则我不需要插入性能)

【问题讨论】:

  • 您可以使用 System.Reflection.Emit 命名空间为您将考虑的每种类型发出一个专门的类。
  • 既然有这么多经过尝试和测试过的ORM,你为什么还要费心编写自己有缺陷的(根据你自己的推理)ORM?与其使用反射,不如尝试代码生成...
  • @Mitch:这是大约 2 年前,我在一周内写的。它完全符合我的需要(本地计算机,没有性能要求。非常易于使用)。现在我需要一些不同的东西。
  • @cdhowie:你什么意思?问题是我反射了 100k 次,这并不是反射有多慢的事实。它只是我想摆脱的开销。
  • @Mitch:有趣的是,实体框架看起来比我的 ORM 更难使用,如果它在每个循环中都进行反射,那么它也会有同样的问题。 (PS:我的语法是var ls = conn.SelectAll<PoDType>("where !col=? AND !col2=?", a, b);,我可以写成func( ls.first().col.data)。非常棒,但对大量的性能不友好)

标签: c# mysql orm


【解决方案1】:

我自己,我会使用现有的 ORM,但为了回答这个问题,这里有一个通过动态生成的 setter 设置属性的简单示例:

void Main()
{
    var setter = GetPropertySetter<MyClass>("MyProperty");

    var myClass = new MyClass();
    setter(myClass, "This was set by the setter");
    Console.WriteLine(myClass.MyProperty);
}

Action<T, object> GetPropertySetter<T>(string propertyName) 
{
    var property = typeof(T).GetProperty(propertyName);
    var target = Expression.Parameter(typeof(T));
    var value = Expression.Parameter(typeof(object));
    var assignment = Expression.Assign(Expression.MakeMemberAccess(target, property), Expression.Convert(value, property.PropertyType));
    var propertyGetterExpression = Expression.Lambda<Action<T, object>>(assignment, target, value);
    return propertyGetterExpression.Compile();
}

class MyClass {
    public string MyProperty { get; set; }
}

(别忘了using System.Linq.Expressions;

【讨论】:

  • 好主意。请注意,这将对每个属性产生函数指针开销。如果 OP 想要对特定类的每个对象执行相同的操作序列,则为每个类编译一个方法会更有效。 (这不是对您的回答的批评,只是对可能阅读此内容的人的另一个想法。)
  • 另外,应该指出每个委托只能编译一次——之后,应该通过某种缓存机制重用之前编译的委托。为每个访问创建一个委托将比使用反射更昂贵。
  • @cdhowie,两者都很好,但最后一个特别需要提及。
【解决方案2】:

Dapper.NET 非常适合自动选择和生成+编译器 CLR 代码,从而变得非常非常快。

【讨论】:

    【解决方案3】:

    我认为您可以使用缓存来保存每种类型的 propertyInfo。

    【讨论】:

    • 可以,但是与 JIT 编译的属性访问相比,GetValue/SetValue 调用仍然相当昂贵。
    猜你喜欢
    • 1970-01-01
    • 2014-05-19
    • 2013-08-19
    • 2013-04-27
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多