【问题标题】:How to get records from tables in custom order of ids?如何以自定义的 id 顺序从表中获取记录?
【发布时间】:2016-09-06 12:48:34
【问题描述】:

我有一些 Ids 存储在下面的变量中:

List<int> Ids;

现在我想根据上面的 ID 获取记录,但顺序与上面Ids.中的顺序相同

例如:数据库中的记录是这样的:

员工:

Id
1
2
3
4
5

现在,如果 Ids 数组包含这样的 Id:4,2,5,3,1,那么我将尝试仅按此顺序获取记录:

查询:

  var data = context.Employee.Where(t => Ids.Contains(t.Id)).ToList();

但上面的查询给我的输出就像在表格中一样:

Id
1
2
3
4
5

预期输出:

Id
4
2
5
3
1

更新:我已经尝试过以下解决方案,但由于这是实体框架,它没有成功:

var data = context.Employee.Where(t => Ids.Contains(t.Id))
                    .OrderBy(d => Ids.IndexOf(d.Id)).ToList();

为了使上述解决方案发挥作用,我必须添加到列表中:

var data = context.Employee.Where(t => Ids.Contains(t.Id)).ToList()
                    .OrderBy(d => Ids.IndexOf(d.Id)).ToList();

但我不想在内存中加载数据然后过滤掉我的记录。

【问题讨论】:

  • 您也需要付出一些努力。请阅读How to Ask 并分享您的研究。这个问题已经被问过很多次了,例如duplicate
  • @CodeCaster 我找不到 Ids 的 Indexof 方法。所以这个问题对你来说是重复的吗?
  • @CodeCaster Indexof 方法不适用于实体框架,因此在将问题标记为重复之前,请仔细阅读问题。谢谢
  • 然后添加一个 .ToList() 。同样,搜索并分享您的研究,这个问题不是唯一的。
  • 更好的做法是使用.AsEnumerable() 而不是.ToList() 来停止数据库端的处理并继续在内存端。后者立即执行查询并创建一个List&lt;T&gt;,而前者仍然是一个延迟执行的查询等等。它只是停止向 SQL 查询添加内容,然后在内存中执行。

标签: c# entity-framework linq


【解决方案1】:

由于未指定ORDER BY 时返回数据的顺序为not determined,因此您必须添加ORDER BY 以指示您希望它如何排序。不幸的是,您必须根据内存中的对象/值进行排序,并且不能使用它在 SQL 查询中进行排序。

因此,您可以做的最好的事情是在从数据库中检索数据后在内存中进行排序。

var data = context.Employee
    // Add a criteria that we only want the known ids
    .Where(t => Ids.Contains(t.Id))
    // Anything after this is done in-memory instead of by the database
    .AsEnumerable()
    // Sort the results, in-memory
    .OrderBy(d => Ids.IndexOf(d.Id))
    // Materialize into a list
    .ToList();

【讨论】:

  • 非常感谢 Maarten 先生的热心帮助。请继续这样的帮助 :)
【解决方案2】:

如果没有存储过程,您可以使用 Union?: 这两个规范函数。
我无法想象其他方式。

?:
您可以使用它为每个 id 值分配一个重量,然后按重量排序。此外,您必须生成 ?: 使用动态 linq。

What is the equivalent of "CASE WHEN THEN" (T-SQL) with Entity Framework?
Dynamically generate LINQ queries

联合
我认为这是更简单的获取方式。在这种情况下,您可以为每个 ID 添加一个 Where/Union。

编辑 1
关于使用 Union 你可以使用类似这样的代码

IQueryable<Foo> query = context.Foos.AsQueryable();
List<int> Ids = new List<int>();
Ids.AddRange(new[] {3,2,1});
bool first = true;
foreach (int id in Ids)
{
    if (first)
    {
        query = query.Where(_ => _.FooId == id);
        first = false;
    }
    else
    {
        query = query.Union(context.Foos.Where(_ => _.FooId == id));
    }
}


var results = query.ToList();

这会生成以下查询

SELECT
[Distinct2].[C1] AS [C1]
FROM ( SELECT DISTINCT
        [UnionAll2].[C1] AS [C1]
        FROM  (SELECT
                [Distinct1].[C1] AS [C1]
                FROM ( SELECT DISTINCT
                        [UnionAll1].[FooId] AS [C1]
                        FROM  (SELECT
                                [Extent1].[FooId] AS [FooId]
                                FROM [Foos] AS [Extent1]
                                WHERE [Extent1].[FooId] = @p__linq__0
                        UNION ALL
                                SELECT
                                [Extent2].[FooId] AS [FooId]
                                FROM [Foos] AS [Extent2]
                                WHERE [Extent2].[FooId] = @p__linq__1) AS [UnionAll1]
                )  AS [Distinct1]
        UNION ALL
                SELECT
                [Extent3].[FooId] AS [FooId]
                FROM [Foos] AS [Extent3]
                WHERE [Extent3].[FooId] = @p__linq__2) AS [UnionAll2]
)  AS [Distinct2]
p__linq__0 = 3
p__linq__1 = 2
p__linq__2 = 1

EDIT 2
我认为最好的方法是内存方法,因为它具有相同的网络负载,EF 不会生成无法工作的丑陋查询在不同于 SQL Server 的数据库上,代码更具可读性。在您的特定应用程序中,可能是那个联合/哪里更好。所以,一般我会建议你尝试内存方法,如果你有[性能]问题,你可以检查 union/where 是否更好。

【讨论】:

  • 您能否提供任何示例,说明在这种情况下我将如何使用联合来达到预期的效果???
  • 见上面的编辑。
  • 我真的很感谢你的回答,这就是我投赞成票的原因,但唯一担心的是哪种方法会更好。记忆方法还是你的方法???
  • 这只是对您问题的回答。我认为更好的方法是内存方法(我在我的应用程序中使用它),因为它具有相同的网络负载,EF 不会生成无法在不同于 SQL Server 的数据库上运行的丑陋查询,并且代码更具可读性。在您的特定应用程序中,可能是那个联合/哪里更好。所以,一般我会建议你尝试内存方法,如果你有[性能]问题,你可以检查 union/where 是否更好。
  • 非常感谢先生的热心帮助,请继续这样的帮助:)
猜你喜欢
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 2015-11-20
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多