【问题标题】:Generate a SQL clause using a Linq-to-Sql Expression使用 Linq-to-Sql 表达式生成 SQL 子句
【发布时间】:2019-07-16 17:30:02
【问题描述】:

我想创建一个可以接受表达式并使用 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)
{
   // ...
}

在函数内部,我想使用 Linq-To-Sql 将条件转换为 SQL 语句。

我知道您可以使用DataContext.Log 查看已执行的查询,并使用DataContext.GetCommand(query).CommandText 在执行前查看完整的查询。但是,我只想生成整个表达式的一部分。

我希望完成的是让我的存储库抽象底层技术(Linq-to-Sql、Dapper 等)。这样我就可以将表达式传递到存储库,让它生成正确的语句并使用正确的技术来执行它。

【问题讨论】:

  • 当你说“只是一部分”时——哪一部分?例子?
  • 本例中的 where 子句
  • 在一般情况下,查询可能需要更多。导航子属性可以添加连接,例如...
  • 同意。我试图找到一个适用于 WHERE 子句的案例,而不是通用的“编写任何表达式并发疯”——如果最终生成的 SQL 无效,我很高兴抛出异常。
  • 您总是可以从生成的查询中解析WHERE 子句。

标签: c# linq-to-sql dapper


【解决方案1】:

你可以这样做:

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

ToString() 为您提供 SQL 表达式。然后,您可以使用正则表达式提取 WHERE 子句。

【讨论】:

    【解决方案2】:

    这是我用来构建自己的谓词以在 Where 函数中使用的代码摘录。编译器无法处理复杂对象的可枚举,所以你必须自己做。

    基本上,代码会传递一个可枚举的(字符串代码,字符串交换)元组,然后构建一个表达式来检索所有具有 Security.Code == tuple.Code AND (Security.MasterExchangeForStocksId == tuple.交换 OR SecurityExchangeId == tuple.exchange)。

    CreateTrEntitiesAsync() 只返回一个实体框架上下文,它具有 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-03
      • 2011-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-01
      • 2011-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多