我看到两个选项,与 LINQ to Entities 保持一致
- 将字典中的数据放在单独的表中,保存,然后加入表。即使您需要每个查询数据,也可以应用此解决方案。
例子:
public class SortKey
{
[Key]
public int SortKeyId { get; set; }
public long SearchId { get; set; }
public int EntityId { get; set; }
public string SortId { get; set; }
}
using (var db = new Db())
{
Dictionary<int, string> dict = new Dictionary<int, string>();
long searchId = DateTime.Now.Ticks; // Simplfied, either use a guid or a FK to another table
db.Keys.AddRange(dict.Select(kv => new SortKey { SearchId = searchId, EntityId = kv.Key, SortId = kv.Value }));
db.SaveChanges();
var query = from e in db.Entity
join k in db.Keys.Where(k => k.SearchId == searchId) on (int)e.Id equals k.EntityId
orderby k.SortId
select e;
}
// Cleanup the sort key table
- 动态构建条件。这可以使用表达式操作来实现
例子:
Expression exp = Expression.Constant(""); //Default order key
var p = Expression.Parameter(typeof(Entity));
foreach (var kv in dict)
{
exp = Expression.Condition(
Expression.Equal(
Expression.Convert(
Expression.MakeMemberAccess(p, p.Type.GetProperty("Id")), typeof(int)
),
Expression.Constant(kv.Key)
),
Expression.Constant(kv.Value),
exp
);
}
var orderByExp = Expression.Lambda<Func<Entity, string>>(exp, p);
var query = db.Entity.OrderBy(orderByExp);
您使用哪个选项取决于字典中的数据量。为OrderBy 构建的条件对于大量数据可能会变得非常低效
编辑
根据更改的问题,您可以使用表达式访问者将 dic[...] 调用替换为字典中每个值的条件测试。这种方法的优点是你可以很容易地改变表达式,替换也会以同样的方式工作
班级:
class DictionaryReplaceVisitor : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if(node.Object != null && node.Object.Type == typeof(Dictionary<int, string>) && node.Method.Name == "get_Item")
{
Expression exp = Expression.Constant(""); //Default order key
// Compile the tahrget of the index and execute it to get the value
// If you know there is a single dictionary you could replace this with a class property intead and set it from the Visit call site,
// but this is the more general appraoch
var dict = Expression.Lambda<Func<Dictionary<int, string>>>(node.Object).Compile()();
foreach (var kv in dict)
{
exp = Expression.Condition(
Expression.Equal(
node.Arguments.Single(),
Expression.Constant(kv.Key)
),
Expression.Constant(kv.Value),
exp
);
}
return exp;
}
return base.VisitMethodCall(node);
}
}
用法:
Expression<Func<Entity, string>> orderByExpression = r => cqh.Contains(r.QuestionID) ? dict[(int)Math.Floor(r.SearchKey1)] + "2" + Guid.NewGuid() :
iqh.Contains(r.QuestionID) ? dict[(int)Math.Floor(r.SearchKey1)] + "1" + Guid.NewGuid() :
dict[(int)Math.Floor(r.SearchKey1)] + "0" + Guid.NewGuid();
var replace = (Expression<Func<Entity, string>>)new DictionaryReplaceVisitor().Visit(orderByExpression);
var query = db.Entity.OrderBy(replace).ToString();
生成的 SQL 不会很漂亮,但它应该可以工作。
解决方案 3:
如果数据量不是很大,可以在查询上做ToList或AsEnumerable,在内存中进行排序(在上述方法之一之后调用OrderBy)。在这种情况下它实际上可能表现更好