【问题标题】:How to use Table-Values parameter with EF Core?如何在 EF Core 中使用 Table-Values 参数?
【发布时间】:2021-05-02 01:06:56
【问题描述】:

我们在 SQL Server 数据库中有自定义类型

CREATE TYPE dbo.UniqueIdentifiers AS TABLE (Identifier UNIQUEIDENTFIER)  

该类型的目的是将其用于查询,我们在其中查找具有提供的标识符的记录。

SELECT * FROM MyRecords WHERE Id IN (@GivenIdentifiers)

我们有许多类似上面的查询,它们被多次调用,使用不同的标识符列表,通过将标识符列表作为 SQL 参数,我们正在提高查询的性能,因为 SQL Server 将使用已经编译的 sql 查询而不是编译新的一个只是因为标识符列表发生了变化。

现在我们将使用 EF Core 作为我们的 SQL Server 数据库应用程序的工作单元,但我无法找到如何使用 EF Core 查询语法使用 Table-Values 参数的方法。

此时我们有

public Order[] LoadOrders(params Guid[] identifiers)
{
    return context.Orders.Where(order => identifiers.Contains(order.Id)).ToArray();
}

使用“硬编码”标识符生成 sql(见下文),当使用不同标识符调用相同方法时,生成的查询会有所不同,这将“强制”SQL Server 再次编译查询,这是我们试图避免的

SELECT * FROM MyRecords WHERE Id IN ('1234abcd-...', '1234abce-...')

我们仍然可以通过“手动”构建查询来使用我们原来的方法,但我们现在希望避免这种情况,因为我们希望能够通过“即时”连接其他表来构建不同的查询(使用 EF核心查询扩展方法)没有为我们使用类似“WHERE”条件的每个表显式引入单独的“构建查询”。

我们如何在 EF Core 中使用表值参数?

【问题讨论】:

  • 这能回答你的问题吗? Entity Framework Stored Procedure Table Value Parameter您基本上需要使用Execute进行直接SQL查询(或exec,如果您有存储过程)
  • @Charlieface,这不是类似的问题。您标记为相似的问题是关于实体框架,它与 EF Core 不同的框架,您标记为相似的问题是关于将值传递给存储过程,这个问题是关于将其与 EF 查询语法一起使用。
  • 100% 抱歉,我错过了。但是解决方法是一样的,根据版本需要FromSqlRaw或者FromSql,直接查询

标签: c# sql-server entity-framework-core


【解决方案1】:

对我们来说,将其他 LINQ 运算符链接到 Where 条件非常重要。

@IvanStoev 感谢您提供链接 Composing with LINQ,基于可组合性,我们能够在下面的实现中使用

-- Create Table-Valued parameter type in database
CREATE TYPE Ids AS TABLE (Id INT);
// Extension method
public static IQueryable<Order> ContainsIds(this IQueryable<Order> source, params int[] ids)
{
    var parameter = ids.ToIdTypeSqlParameter();
    var sql = $"SELECT * FROM [Order] o WHERE EXISTS (SELECT 1 FROM {p.ParameterName} i WHERE i.Id = o.Id)";
    return source.FromSql(sql, parameter);
}

用法:

var result = await context.Orders
    .ContainsIds(1, 2, 3, 4) 
    .Where(order => order.CreatedAt > 20.January(2020))
    .Select(order => new { order.Id, order.Name, order.TotalPrice })
    .ToArrayAsync();

【讨论】:

    【解决方案2】:

    EFCore 支持结构化参数,可用于将 DataTable 序列化为用户定义的表值。 IN() 语句支持的值数量是有限制的。为了绕过这个限制,我有时会传输一个数据表作为用户定义的 TVP。

      var myDataTable = FillDataTableWithData();
      var paramTable= new SqlParameter
      {
           ParameterName = '@MyIntIDTable',
           SqlDbType = SqlDbType.Structured,
           Value = myDataTable
      }
      await _dbContext.Database.ExecuteSqlRawAsync("BulkValidation {0}", paramTable);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-26
      • 2022-06-11
      • 2018-12-05
      • 1970-01-01
      • 2021-07-31
      • 2019-10-07
      • 2019-12-04
      相关资源
      最近更新 更多