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

时间:2011-02-22 02:38:44

标签: c# entity-framework lambda

库或代码是否可用于从lambda表达式创建SQL Update语句?我们希望使用强类型的lambda表达式来进行更新,而不是事先调用对象或使用字符串。我在考虑这样的事情。

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

大致会转化为......

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

我应该提到我们目前正在使用Entity Framework和Postgres。

4 个答案:

答案 0 :(得分:7)

我终于想出办法来做到这一点。基本上,从实体框架,LINQ-to-SQL或其他ORM获取生成的SQL,然后解析WHERE子句。这样我就不必手动解析lambda了。然后从匿名类型创建UPDATE子句。结果如下:

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");

这允许我更新/删除值而不先拉它们。

它的代码看起来像这样......

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\"");
}

答案 1 :(得分:2)

你可以像这样做某些,但是对于可以翻译成SQL的内容以及需要将其拉回到你的应用程序的内容会有限制。

您需要做的是为Update方法提供Action(这是'更新'部分)和Expression(作为'where'子句)。< / p>

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.
}

然后,您可以使用类似

的内容调用更新
repository.Update(s => s.Name = "Me", w => w.Id == 4);

答案 2 :(得分:2)

对于那些喜欢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);
    }

用法:

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

在EF6上测试

答案 3 :(得分:1)

我发现这篇文章是关于构建和执行“实体框架顶部的SQL更新”。也许它对你有用。

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

相关问题