根据带有LINQ的ID列表,按顺序选择多行

时间:2017-08-24 20:35:27

标签: sql-server performance entity-framework linq

我有一份ID列表。如何选择id在列表中的所有行并保留顺序?

这就是我所拥有的:

var ids = new int[]{5, 1, 8, 2, 3};
var items = Db.Items.Where(x => ids.Contains(x.Id));

但它不会保留订单。

我知道我可以根据ID对项目进行排序,但我希望O(n)复杂。

此问题类似于:Select multiple records based on list of Id's with linq,但我需要按顺序保留行

4 个答案:

答案 0 :(得分:3)

我没有那么多的查询和数据库,但你只需要做C#技巧就可以很快完成这个任务

before(done => {
  mongoose.connect('mongodb://localhost/test', { useMongoClient : true });
  mongoose.Promise = global.Promise;

  mongoose.connection
    .once('open', () => done())
    .on('error', err => console.err('Db connection error', err);
  });
});

我无法告诉它如何被翻译成数据库查询

我还没有对其进行测试,但这里的版本没有var ids = new int[]{5, 1, 8, 2, 3}; var dict = ids.Select((id, i) => new { Index = i, Id = id }) .ToDictionary(x => x.Id, x => x.Index); var items = Db.Items .Where(x => ids.Contains(x.Id)) .OrderBy(x => dict[x.Id]); ,但空间效率较低(实际上可能更慢):

OrderBy

还有另一种方法 - 只需进行反向连接:

var ids = new int[]{5, 1, 8, 2, 3};
var temp = Db.Items
.Where(x => ids.Contains(x.Id))
.ToLookup(x => x.Id);

var tempList = new List<IGrouping<int, Item>>();
for(int i = 0; i < ids.Length; i++)
{
    tempList.Add(temp[ids[i]]);
}

var items = tempList.SelectMany(x => x);

这将导致按ids

排序的查询

答案 1 :(得分:1)

如何投影到中间类型以保留原始索引,构建联合以及对索引进行排序?

class ItemWithIndex
{
    public int Index { get; set; }
    public Item Item { get; set; }
}

class Item
{
    public int Id { get; set; }
}

int[] ids = { 5, 1, 8, 2, 3 };

IQueryable<ItemWithIndex> query = null;

for(int index = 0; index < ids.Length; index++)
{
    int currentIndex = index;
    int currentId = ids[index];

    IQueryable<ItemWithIndex> next = db.Items
        .Where(i => i.Id == currentId)
        .Select(i => new ItemWithIndex { Index = currentIndex, Item = i });

    query = query == null ? next : query.Concat(next);
}

ItemWithIndex[] items = query
    .OrderBy(i => i.Index)
    .ToArray();

以下是生成的查询:

SELECT 
    [UnionAll4].[Id] AS [C1], 
    [UnionAll4].[C1] AS [C2], 
    [UnionAll4].[Id1] AS [C3]
    FROM  (SELECT 
        [Extent1].[Id] AS [Id], 
        @p__linq__1 AS [C1], 
        [Extent1].[Id] AS [Id1]
        FROM [dbo].[Items] AS [Extent1]
        WHERE [Extent1].[Id] = @p__linq__0
    UNION ALL
        SELECT 
        [Extent2].[Id] AS [Id], 
        @p__linq__3 AS [C1], 
        [Extent2].[Id] AS [Id1]
        FROM [dbo].[Items] AS [Extent2]
        WHERE [Extent2].[Id] = @p__linq__2
    UNION ALL
        SELECT 
        [Extent3].[Id] AS [Id], 
        @p__linq__5 AS [C1], 
        [Extent3].[Id] AS [Id1]
        FROM [dbo].[Items] AS [Extent3]
        WHERE [Extent3].[Id] = @p__linq__4
    UNION ALL
        SELECT 
        [Extent4].[Id] AS [Id], 
        @p__linq__7 AS [C1], 
        [Extent4].[Id] AS [Id1]
        FROM [dbo].[Items] AS [Extent4]
        WHERE [Extent4].[Id] = @p__linq__6
    UNION ALL
        SELECT 
        [Extent5].[Id] AS [Id], 
        @p__linq__9 AS [C1], 
        [Extent5].[Id] AS [Id1]
        FROM [dbo].[Items] AS [Extent5]
        WHERE [Extent5].[Id] = @p__linq__8) AS [UnionAll4]

答案 2 :(得分:1)

我会说,

1,您可以像以前一样获得这些物品:

var ids = new int[]{5, 1, 8, 2, 3};
var items = Db.Items.Where(x => ids.Contains(x.Id));

然后你可以做类似的事情:

var orderedItems = new int[ids.Length()] // sorry, I'm codign in SO edit, not sure on the syntax
foreach(id in items)
{
var position = Array.IndexOf(items, id)
orderedITems[position] = id;
}

那应该按照你的要求做(也可以简化为一行)。

我希望它有所帮助,

答案 3 :(得分:0)

这是一个可能的解决方案:

var ids = new int[] {5, 1, 8, 2, 3};
var items = new List<Item>();
for (int i = 0; i < ids.Length; i++)
{
    items.Add(Db.Items.Find(ids[i]));
}

然而,它执行N个查询,因此应该有更好的方法。