Создать предложение SQL с помощью выражения Linq-to-Sql - PullRequest
3 голосов
/ 23 ноября 2011

Я хотел бы создать модель репозитория, которая могла бы принимать выражение и использовать Linq-To-Sql для генерации требуемого оператора SQL.

Например, у меня есть такая функция:

// Possible criteria
Expression<Func<Purchase,bool>> criteria1 = p => p.Price > 1000;

// Function that should take that criteria and convert to SQL statement
static IEnumerable<Customer> GetCustomers (Expression<Func<Purchase,bool>> criteria)
{
   // ...
}

Внутри функции я хотел бы преобразовать критерии в оператор SQL с помощью Linq-To-Sql.

Я знаю, что вы можете использовать DataContext.Log для просмотра выполненных запросов и DataContext.GetCommand(query).CommandText чтобы увидеть полный запрос перед его выполнением.Однако мне бы хотелось, чтобы сгенерировалась только часть всего выражения.

Чего я надеюсь добиться, так это сделать мой репозиторий абстрагирующимся от базовой технологии (Linq-to-Sql, Dapper и т.д.)Таким образом, я мог передать выражение в хранилище, сгенерировать правильное выражение и использовать правильную технологию для его выполнения.

Ответы [ 2 ]

1 голос
/ 16 июля 2019

Это фрагмент кода, который я использую для создания собственного предиката для использования в функции Where.Компилятор не может справиться с многочисленными сложными объектами, поэтому вы должны сделать это сами.

По сути, код передается через множество кортежей (строковый код, обмен строк), а затем создает выражение дляполучить все объекты безопасности, имеющие Security.Code == tuple.Code AND (Security.MasterExchangeForStocksId == tuple.exchange ИЛИ SecurityExchangeId == tuple.exchange).

CreateTrEntitiesAsync () просто возвращает контекст Entity Framework, которыйимеет свойство безопасности DbSet.

public async Task<Security[]> GetSecurities(IEnumerable<(string code, string exchange)> tickers)
{
    using (var ctx = await CreateTrEntitiesAsync())
    {
        var securityExpr = Expression.Parameter(typeof(Security), "security");
        Expression expr = null;
        Expression exprToadd;

        foreach (var item in tickers)
        {
            exprToadd = Expression.And(
                Expression.Equal(Expression.Property(securityExpr, nameof(Security.Code)), Expression.Constant(item.code)),
                Expression.Or(
                    Expression.Equal(Expression.Property(Expression.Property(securityExpr, nameof(Security.Exchange)), nameof(Exchange.MasterExchangeForStocksId)), Expression.Constant(item.exchange)),
                    Expression.Equal(Expression.Property(securityExpr, nameof(Security.ExchangeId)), Expression.Constant(item.exchange))
                )
            );

            if (expr == null)
                expr = exprToadd;
            else
                expr = Expression.Or(expr, exprToadd);
        }

        var criteria = Expression.Lambda<Func<Security, bool>>(expr, new ParameterExpression[] { securityExpr });
        var items = ctx.Securities.Where(criteria);
        return await items.ToArrayAsync();
    }
}
1 голос
/ 23 ноября 2011

Вы можете сделать что-то вроде этого:

string sql = DataContext.GetTable<Customer>().Where(criteria).ToString();

ToString () дает вам выражение SQL. Затем вы можете использовать регулярное выражение, чтобы вынуть предложение WHERE.

...