【问题标题】:How to Convert Lambda Expression To Sql?如何将 Lambda 表达式转换为 Sql?
【发布时间】:2012-06-14 07:03:15
【问题描述】:

我正在开发一个小框架来访问数据库。我想添加一个使用 lambda 表达式进行查询的功能。我该怎么做?

public class TestModel
{
    public int Id {get;set;}
    public string Name {get;set;}
}

public class Repository<T>
{
    // do something.
}

例如:

var repo = new Repository<TestModel>();

var query = repo.AsQueryable().Where(x => x.Name == "test"); 
// This query must be like this:
// SELECT * FROM testmodel WHERE name = 'test'

var list = query.ToDataSet();
// When I call ToDataSet(), it will get the dataset after running the made query.

【问题讨论】:

  • linqpad.net 可以帮助你。
  • 您应该使用启用 LINQ over Expressions 的 O/RM 框架,例如 LINQ to SQL 或实体框架。
  • 你想实现query provider吗?
  • @sinanakyazici:编写自己的查询提供程序非常复杂!不要浪费你老板的钱写你自己的。无论如何你都会失败。只需使用 Entity Framework (.NET 3.5) 的第一个版本(并了解 EF1 有多糟糕)即可了解编写自己的引擎以允许将表达式树转换为 SQL 是多么复杂。
  • 要了解 LINQ 的深度,请观看this

标签: c# linq lambda asqueryable


【解决方案1】:

继续创建一个LINQ Provider(我相信你不想这样做,无论如何)。

工作量很大,所以也许您只想使用NHibernateEntity Framework 或类似的东西。

如果您的查询相当简单,也许您不需要成熟的 LINQ 提供程序。查看Expression Trees(由 LINQ 提供者使用)。

你可以破解这样的东西:

public static class QueryExtensions
{
    public static IEnumerable<TSource> Where<TSource>(this Repo<TSource> source, Expression<Func<TSource, bool>> predicate)
    {
        // hacks all the way
        dynamic operation = predicate.Body;
        dynamic left = operation.Left;
        dynamic right = operation.Right;

        var ops = new Dictionary<ExpressionType, String>();
        ops.Add(ExpressionType.Equal, "=");
        ops.Add(ExpressionType.GreaterThan, ">");
        // add all required operations here            

        // Instead of SELECT *, select all required fields, since you know the type
        var q = String.Format("SELECT * FROM {0} WHERE {1} {2} {3}", typeof(TSource), left.Member.Name, ops[operation.NodeType], right.Value);
        return source.RunQuery(q);
    }
}
public class Repo<T>
{
    internal IEnumerable<T> RunQuery(string query)
    {
        return new List<T>(); // run query here...
    }
}
public class TestModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var repo = new Repo<TestModel>();
        var result = repo.Where(e => e.Name == "test");
        var result2 = repo.Where(e => e.Id > 200);
    }
}

请不要按原样使用它。这只是一个快速而肮脏的示例,如何分析表达式树以创建 SQL 语句。

为什么不直接使用 Linq2Sql、NHibernate 或 EntityFramework...

【讨论】:

  • 我尝试使用 linq 提供程序。我确实解释了。但它没有用。课太多了。我不做一个更简单的方法吗?
  • @sinanakyazici 我添加了一个简单的例子让你明白
  • @sinanakyazici 是的,创建 linq 提供程序很复杂。这就是为什么人们不用自己写,而是使用现有的。
  • 非常感谢。你写了另一个 Where()。但我想使用 Linq 的 Where()。所以你写的对我没用。据推测,我可以使用 Linq Provider。
  • 为什么我不使用它们(Linq2Sql、NHibernate 和 EntityFR)?因为我已经写在我的 ORM 中了。所以我不需要它们。
【解决方案2】:

如果你想做类似的事情

db.Employee
.Where(e => e.Title == "Spectre")
.Set(e => e.Title, "Commander")
.Update();

db
.Into(db.Employee)
    .Value(e => e.FirstName, "John")
    .Value(e => e.LastName,  "Shepard")
    .Value(e => e.Title,     "Spectre")
    .Value(e => e.HireDate,  () => Sql.CurrentTimestamp)
.Insert();

db.Employee
.Where(e => e.Title == "Spectre")
.Delete();

然后看看这个,BLToolkit

【讨论】:

    【解决方案3】:

    你可能想看看http://iqtoolkit.codeplex.com/,它非常复杂,我不建议你从头开始构建。

    我刚刚写了一些接近 dkons 答案的东西,无论如何我都会添加它。只是使用流畅的界面而已。

    public class Query<T> where T : class
    {
        private Dictionary<string, string> _dictionary;
    
        public Query()
        {
            _dictionary = new Dictionary<string, string>();
        } 
    
        public Query<T> Eq(Expression<Func<T, string>> property)
        {
            AddOperator("Eq", property.Name);
            return this;
        }
    
        public Query<T> StartsWith(Expression<Func<T, string>> property)
        {
            AddOperator("Sw", property.Name);
            return this;
        }
    
        public Query<T> Like(Expression<Func<T, string>> property)
        {
            AddOperator("Like", property.Name);
            return this;
        }
    
        private void AddOperator(string opName, string prop)
        {
            _dictionary.Add(opName,prop);
        }
    
        public void Run(T t )
        {
            //Extract props of T by reflection and Build query   
        }
    }
    

    假设你有一个类似的模型

    class Model
        {
            public string Surname{ get; set; }
            public string Name{ get; set; }
        }
    

    您可以将其用作:

    static void Main(string[] args)
            {
    
                Model m = new Model() {Name = "n", Surname = "s"};
                var q = new Query<Model>();
                q.Eq(x => x.Name).Like(x=>x.Surname).Run(m);
    
    
            }
    

    【讨论】:

    • Property.Name 始终为空。为了提取它,您必须执行以下操作: var expression = (MemberExpression)property.Body; string name = expression.Member.Name;
    • 另一件事是你不能使用 dic 认为如果你有两次“LIKE”,那么会发生什么?
    猜你喜欢
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多