在Linq to Entity Framework Query中按数组值排序

时间:2015-12-14 09:10:00

标签: c# entity-framework linq

我正在尝试在Linq to EntityFramework查询中编写OrderBy子句。我的问题是我正在查看的实体表存储了一个ID,它与不同数据库中的表有关,我无法调整数据库。

MainDatabase.EntityToOrder

ID
Name
OtherID

SecondDatabase.OtherEntity

ID
Name

我的C#EntityToOrder模型看起来像这样,我需要能够通过" OtherName"

订购

EntityToOrder.cs

public class EntityToOrder
{
    [DataMember]
    public long ID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public long OtherId { get; set; }

    public string OtherName { get; set; }
}

所以,我想通过" OtherName"来订购EntityToOrder。以最有效的方式。我现有的查询看起来像这样。

var entities = mainContext.EntityToOrder.OrderBy(e => e.Name).Skip(startIndex).Take(pageSize).ToList();

var otherIds = entities.Select(e => e.OtherID).ToList();
Dictionary<long, string> otherNames = secondContext.OtherEntity
    .Where(oe => otherIds.Contains(oe.ID))
    .Select(oe => new { ID = oe.ID, Name = oe.Name })
    .ToDictionary(oe => oe.ID, oe => oe.Name);

entities.ForEach(e => OtherName = otherNames[e.OtherID]);

如何通过&#34; OtherName&#34;编写最有效的查询,最好避免将整个EntityToOrder表选入内存。

更新

为清楚起见,这里有一些实现OrderBy的代码,但需要将整个EntityToOrder表检索到内存中。我希望能以更有效的方式实现这一目标。此外,OtherEntity可以属于许多EntityToOrder行。

var entities = mainContext.EntityToOrder.ToList();
var otherIds = entities.Select(e => e.OtherID).ToList();
Dictionary<long, string> otherNames = secondContext.OtherEntity
    .Where(oe => otherIds.Contains(oe.ID))
    .Select(oe => new { ID = oe.ID, Name = oe.Name })
    .ToDictionary(oe => oe.ID, oe => oe.Name);

entities.ForEach(e => OtherName = otherNames[e.OtherID]);
return entities.OrderBy(e => e.OtherName).Skip(startIndex).Take(pageSize).ToList();

3 个答案:

答案 0 :(得分:1)

非常具有挑战性的任务。我最初只想在OtherEntity表上切换角色并执行分页(OrderBy / Skip / Take),但不幸的是,由于一对多的关系,它不起作用。所以我最终在OtherEntity的内存中做了一些预分页。但是,为了做到这一点,我需要EnityToOrder中匹配项的计数,所以这是通过额外的db查询检索的,这使得该解决方案涉及3个db查询和一些内存处理。这是

var countByOtherId = db.EntityToOrder
    .GroupBy(e => e.OtherId)
    .Select(g => new { ID = g.Key, Count = g.Count() })
    .ToDictionary(e => e.ID, e => e.Count);

var other = new Dictionary<long, string>();
int skipCount = startIndex, useCount = 0;
foreach (var e in db.OtherEntity.OrderBy(e => e.Name))
{
    int count;
    if (!countByOtherId.TryGetValue(e.ID, out count)) continue;
    if (skipCount > 0 && other.Count == 0)
    {
        if (skipCount >= count) { skipCount -= count; continue; }
        count -= skipCount;
    }
    other.Add(e.ID, e.Name);
    if ((useCount += count) >= pageSize) break;
}


var entities = db.EntityToOrder
    .Where(e => other.Keys.Contains(e.OtherId))
    .AsEnumerable()
    .Select(e => new EntityToOrder { ID = e.ID, Name = e.Name, 
        OtherId = e.OtherId, OtherName = other[e.OtherId] })
    .OrderBy(e => e.OtherName).ThenBy(e => e.Name)
    .Skip(skipCount).Take(pageSize)
    .ToList();

现在,我不太确定你现在做的事情是否更好,但值得尝试。

答案 1 :(得分:0)

如果您可以更改模型,则可以尝试以下操作:

public class EntityToOrder
{
    [DataMember]
    public long ID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public long OtherId { get; set; }

    [ForeignKey("OtherId")]
    public OtherEntity OtherEntity{ get; set; }
}

然后,您应该能够执行此查询:

using System.Data.Entity;

var entities = mainContext
    .EntityToOrder
    .Include(x => x.OtherEntity)
    .OrderBy(e => e.OtherEntity.Name)
    .Skip(startIndex)
    .Take(pageSize)
    .ToList();

修改: 对不起,我错过了你有两个数据库....

答案 2 :(得分:0)

我发现了一个替代方案,我想我会发布以防任何人都有用。我使用.Join()将OtherEntity的字典合并到我的查询中。这仍然选择IEnumerable,所以我认为它不是更有效。

var entities = mainContext.EntityToOrder;
var otherIds = entities.Select(e => e.OtherID).ToList();

Dictionary<long, string> otherNames = secondContext.OtherEntity
    .Where(oe => otherIds.Contains(oe.ID))
    .Select(oe => new { ID = oe.ID, Name = oe.Name })
    .ToDictionary(oe => oe.ID, oe => oe.Name);

Func<EntityToOrder, KeyValuePair<long, string>, EntityToOrder> joinFunc = ((a, b) => { 
    a.OtherName= b.Value;
    return a;
});

return entities.Join(otherNames, e => e.OtherID, oe => oe.Key, joinFunc)
    .OrderBy(e => e.OtherName)
    .Skip(startIndex)
    .Take(pageSize)
    .ToList();

有关包含的说明

应用Join时,您选择进入IEnumerable,因此无法访问链接表中的属性。要解决此问题,您需要在应用.Join()之前为需要访问的任何链接表添加.Include()。 E.g。

var entities = mainContext.EntityToOrder
    .Include("LinkedEntity");

return entities.Join(otherNames, e => e.OtherID, oe => oe.Key, joinFunc)
    .OrderBy(e => e.OtherName)
    .ThenBy(e => e.LinkedEntity.Name) //reference to linked table
    .ToList();
相关问题