简体   繁体   中英

Linq-to-Entities contains and order by

I use EF Core and I want to select only the IDs I need, as I would do it, I use an In SQL expression. How can I get the result in the same order as the Ids in the array? And fill OrderNum value in result Dto?

public IEnumerable<ResultDto> Foo()
{
    int[] validIds = { 100, 2, 3, 4, 5, 6, 8, 13, 14, 16, 22 };

    // Without the required sorting
    var query = dc.LeaveRequests.Where(x => validIds.Contains(x.Id));

   ...
}

class Model
{
     public int Id { get; set; }
     public string Name { get; set; }
}

class ResultDto
{
     public int Id { get; set; }
     public string Name { get; set; }
     public int OrderNum { get; set; }
}

I would create an index lookup dictionary with the ID as the key and the index as the value. You can then order the result by looking up the index in the dictionary in O(1) time. (using .IndexOf on the array would be an O(n) operation)

int[] validIds = { 100, 2, 3, 4, 5, 6, 8, 13, 14, 16, 22 };
var result = dc.LeaveRequests.Where(x => validIds.Contains(x.Id)).AsEnumerable();
    
var indexLookup = validIds.Select((v,i) => (v,i)).ToDictionary(x => x.v, x => x.i);
var sortedResult = result.OrderBy(x => indexLookup[x.Id]);

Perhaps an even more simple solution would be to join the validIds with the result of the query. The order from the first collection is preserved and the join will use a HashSet internally for the lookup. It would also perform better since ordering the result using OrderBy can be avoided.

int[] validIds = { 100, 2, 3, 4, 5, 6, 8, 13, 14, 16, 22 };
var result = dc.LeaveRequests.Where(x => validIds.Contains(x.Id)).AsEnumerable();

var sortedResult = validIds.Join(result, x => x, x => x.Id, (x, y) => y);

Try OrderBy if you don't have more requirements.

var query = dc.LeaveRequests
     .Where(x => validIds.Contains(x.Id))
     .OrderBy(x => validIds.IndexOf(x.Id))
     .Select(x => new OrderNum {
          Id = x.Id,
          Name = x.Name,
          OrderNum = //fill OrderNum here,

     })
     .AsEnumerable();

Assuming that the valid ids may be provided in another order, you could order by the index position of the id in the validIds (using a list instead of an array) and map the index position of the result to the OrderNum property:

var query = dc.LeaveRequests
    .Where(x => validIds.Contains(x.Id))
    .OrderBy(x => validIds.IndexOf(x.Id))
    .Select((x, i) => new ResultDto
    {
        Id = x.Id,
        Name = x.Name,
        OrderNum = i
    });
var results = dc.LeaveRequests
    .Where(x => validIds.Contains(x.Id))
    .Select(x => new ResultDto
    {
        Id = x.Id,
        Name = x.FechaCreacion,
    })
    .AsEnumerable()
    .OrderBy(x => validIds.IndexOf(x.Id))
    .ToList();

for (int i = 0; i < results.Count; i++)
{
    results[i].OrderNum = i;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM