简体   繁体   English

使用C#将Lambda表达式转换为SQL UPDATE语句

[英]Lambda expression to SQL UPDATE statement using C#

Is library or code available to create SQL Update statements from lambda expressions? 库或代码是否可用于从lambda表达式创建SQL Update语句? We would like to use strongly-typed lambda expressions to do updates instead of calling the object before hand, or using strings. 我们希望使用强类型的lambda表达式来进行更新,而不是事先调用对象或使用字符串。 I'm thinking of something like this. 我在考虑这样的事情。

Update<Task>(
    u => u.UserID = 1, u.TaskCount += 1, //Update
    w => w.Priority != "High" && (w.Status != "Complete" || w.Status == null) //Where
);

Which would roughly translate to.. 哪个会粗略地翻译成..

UPDATE Tasks SET UserID = 1, TaskCount = TaskCount + 1
WHERE Priority <> "High" AND (Status <> "Complete" OR Status = null)

I should mention we are currently using the Entity Framework and Postgres. 我应该提到我们目前正在使用Entity Framework和Postgres。

I finally figured out a way to do this. 我终于想出办法来做到这一点。 Basically, get the generated SQL from the Entity Framework, LINQ-to-SQL, or another ORM, then parse the WHERE clause. 基本上,从实体框架,LINQ-to-SQL或其他ORM获取生成的SQL,然后解析WHERE子句。 That way I don't have to parse the lambda manually. 这样我就不必手动解析lambda了。 Then create an UPDATE clause from an anonymous type. 然后从匿名类型创建UPDATE子句。 The result looks like: 结果如下:

Update<Task>(
    new { UserID = 1, TaskCount = IncrementOf(1), SomeOtherField = DdNull } //Update
    w => w.Priority != "High" && (w.Status != "Complete" || w.Status == null) //Where
);

Delete<Task>(w => w.UserID == userID && w.Status != "Complete");

This allows me to update/delete values WITHOUT pulling them first. 这允许我更新/删除值而不先拉它们。

And the code for it looks like this... 它的代码看起来像这样......

protected void Update<T>(object values, Expression<Func<T, bool>> where) where T : class
{
    Domain.ExecuteStoreCommand(
        "UPDATE {0} SET {1} WHERE {2};",
        GetTableString<T>(),
        GetUpdateClauseString(values),
        GetWhereClauseString(where)
        );
}

protected string GetUpdateClauseString(object obj)
{
    string update = "";
    var items = obj.ToDictionary();
    foreach (var item in items)
    {
        //Null
        if (item.Value is DBNull) update += string.Format("{0} = NULL", GetFieldString(item.Key));

        //Increment
        else if (item.Value is IncrementExpression) update += string.Format("{0} = {0} + {1}", GetFieldString(item.Key), ((IncrementExpression)item.Value).Value.ToString());

        //Decrement
        else if (item.Value is DecrementExpression) update += string.Format("{0} = {0} - {1}", GetFieldString(item.Key), ((DecrementExpression)item.Value).Value.ToString());

        //Set value
        else update += string.Format("{0} = {1}", GetFieldString(item.Key), GetValueString(item.Value));

        if (item.Key != items.Last().Key) update += ", ";
    }
    return update;
}

protected string GetWhereClauseString<T>(Expression<Func<T, bool>> where) where T : class
{
    //Get query
    var query = ((IQueryable<T>)Domain.CreateObjectSet<T>());
    query = query.Where(where);
    ObjectQuery queryObj = (ObjectQuery)query;

    //Parse where clause
    string queryStr = queryObj.ToTraceString();
    string whereStr = queryStr.Remove(0, queryStr.IndexOf("WHERE") + 5);

    //Replace params
    foreach (ObjectParameter param in queryObj.Parameters)
    {
        whereStr = whereStr.Replace(":" + param.Name, GetValueString(param.Value));
    }

    //Replace schema name
    return whereStr.Replace("\"Extent1\"", "\"Primary\"");
}

And for those who like Extensions: 对于那些喜欢扩展的人:

public static async Task Update<T>(this DbSet<T> objectContext, Action<T> updateStatement, Expression<Func<T, bool>> where) where T : class
    {
        var items = objectContext.AsQueryable();

        // filter with the Expression if exist
        if (where != null)
            items = items.Where(where);

        // perform the Action on each item
        await items.ForEachAsync(updateStatement);
    }

Usage: 用法:

await context.Organisations.Update(s => s.LastDateBasicEvent = LastDayOfSchool, null);
context.SaveChanges();

Tested on EF6 在EF6上测试过

You can do something like this, but there will be limitations on what can be translated into SQL and what needs to be pulled back to your application. 你可以做这样的事情 ,但不会有什么可以转化为SQL,需要拉回你的应用有什么限制。

What you need to do is give your Update method both an Action (this is the 'update' part) and an Expression (as the 'where' clause). 你需要做的是给你的Update方法一个Action (这是'update'部分)和一个Expression (作为'where'子句)。

public void Update(Action<T> updateStatement, Expression<Func<T, bool>> where)
{
    // get your object context & objectset, cast to IQueryable<T>
    var table = (IQueryable<T>)objectContext.CreateObjectSet<T>();        

    // filter with the Expression
    var items = table.Where(where);

    // perform the Action on each item
    foreach (var item in items)
    {
        updateStatement(item);
    }

    // save changes.
}

Then you can call your Update with something like 然后你可以用类似的东西来调用你的更新

repository.Update(s => s.Name = "Me", w => w.Id == 4);

I found this article about building and executing an "SQL update on-top of the Entity Framework". 我发现这篇文章是关于构建和执行“实体框架顶部的SQL更新”。 Maybe it's useful for you. 也许它对你有用。

http://blogs.msdn.com/b/alexj/archive/2007/12/07/rolling-your-own-sql-update-on-top-of-the-entity-framework-part-1.aspx http://blogs.msdn.com/b/alexj/archive/2007/12/07/rolling-your-own-sql-update-on-top-of-the-entity-framework-part-1.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM