Лямбда-выражение в оператор SQL UPDATE с использованием C # - PullRequest
4 голосов
/ 22 февраля 2011

Доступна ли библиотека или код для создания операторов SQL Update из лямбда-выражений?Мы хотели бы использовать лямбда-выражения со строгой типизацией для обновления, вместо того, чтобы вызывать объект заранее или использовать строки.Я думаю о чем-то вроде этого.

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 ]

7 голосов
/ 09 марта 2011

Я наконец-то нашел способ сделать это.По сути, получите сгенерированный SQL из Entity Framework, LINQ-to-SQL или другого ORM, а затем проанализируйте предложение WHERE.Таким образом, мне не нужно разбирать лямбду вручную.Затем создайте предложение 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\"");
}
2 голосов
/ 05 августа 2014

А для тех, кто любит расширения:

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

2 голосов
/ 22 февраля 2011

Вы можете сделать что-то подобным образом, но будут ограничения на то, что может быть переведено в SQL, и что необходимо вернуть в ваше приложение.

То, что вам нужно сделать, это дать вашему 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.
}

Затем вы можете вызвать обновление с помощью

.
repository.Update(s => s.Name = "Me", w => w.Id == 4);
1 голос
/ 21 сентября 2011

Я нашел эту статью о создании и выполнении «SQL-обновления поверх Entity Framework». Может быть, это полезно для вас.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...