【问题标题】:Query many objects by list of ids with ef core and no User-Defined Table Types通过具有 ef 核心且没有用户定义的表类型的 id 列表查询许多对象
【发布时间】:2020-12-17 18:27:29
【问题描述】:

我有一个我想要获取的对象的 ID 列表。列表可能很大 context.MyObject.Where(obj=> myIdList.Contains(obj.Id))。可能有超过 10000 个条目。

解决方案应该是创建一个临时表,如下所示:Create temporary list/table in SqlServer。我可以在 SQL 中使用值来执行此操作,并通过连接选择我需要的行。它看起来像这样:

declare @idTable table (Id int)
insert into @idTable values (1), (2), (5), (7), (10)....

select MyTable.* from MyTable
inner join @idTable as ids on ids.Id= MyTable.Id

here 所示,使用 ef core 也可以实现类似的功能:

DataTable table = new DataTable();
table.Columns.Add(new DataColumn("Id", typeof(int)));
        
foreach (int id in myIdList)
{
    DataRow row = table.NewRow();
    row["Id"] = v.FieldId;
   
    table.Rows.Add(row);
}

var param = new SqlParameter("@idTable", table) { TypeName = "dbo.CustomSqlType", SqlDbType = SqlDbType.Structured };
var myObjects = context.MyObject.FromRawSql("select MyTable.* from MyTable
inner join @idTable as ids on ids.Id= MyTable.Id", param);

但是为了在 ef-core 中工作,我需要用户定义的表类型。由于数据库的性质,我不想这样做。这 -> TypeName = "dbo.CustomSqlType" 丢失了,我无法在服务器上创建它。上面的 sql 表明没有它是可能的。 创建用户定义表类型的另一种方法是每次执行时都创建一个大的 sql 字符串。出于安全原因,我不想这样做(我不相信自己会逃避,我也不应该这样做)并且我希望能够重用代码,以便我可以通过 idLists 从其他表中检索对象。 是否可以在 ef-core 中以可重用的方式在没有用户定义的表类型的情况下做我想做的事情?


如果这在 ef-core 中是不可能的,我也很乐意为 .netcore 提供另一个框架或工具的替代方案。

【问题讨论】:

  • 你试过基础版吗? var ids = new [] { 1, 2, 5, 7, 10 }; context.MyObject.Where(e => ids.Contains(e.id))?
  • @AluanHaddad 是的。正如我所说的那样,列表太大了。服务器超时,我认为通常应该避免包含超过 1000 个列表条目,因为它非常低效。
  • 您是否尝试过将所有内容都包含在FromSql 中?
  • @AluanHaddad 不,但我更喜欢一个能够以正常方式转义 sql 参数的解决方案,但如果没有其他可能,我会尝试。
  • 我明白你在说什么,UDF 怎么样?

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


【解决方案1】:

替代方法:

在数据库中创建一个包含两个字段的模型(表)

public class SelectedRecord
{
     public Guid GroupId { get; set; }
     public Guid RecordId { get; set; }
}

然后在查询数千条记录之前,插入你要选择的记录

var groupId = Guid.NewGuid();
var selectedRecords = 
    ids.Select(id => new SelectedRecord { GroupId = groupId, RecordId = id })
       .ToArray();
context.SelectedRecords.AddRange(selectedRecords);

var objects = context.SelectedRecords
    .Where(selected => selected.GroupId == groupId)
    .Join(context.MyObjects,
        selected => selected.RecordId,
        object => object.Id,
        (_, object) => object
     )
     .ToArray();

当然,这需要插入数千条记录,但插入只有两列的表比运行IN (id1, id2, ..., id99999) 更快

【讨论】:

  • 它不是完美的解决方案,但我认为它是最干净的,不用担心接触现有的东西
猜你喜欢
  • 2020-08-05
  • 1970-01-01
  • 2019-10-13
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 2013-10-07
相关资源
最近更新 更多