我试图将orderByExpression传递给在实体框架中的dbContext对象上使用它的函数
> Dictionary<int, string> dict = new Dictionary<int, string>();
> Expression<Func<DbQuestion, string>> orderByExpression = r => dict[r.Id];
这会引发以下错误。
Exception = Exceptions.DBConnectionException:LINQ to Entities无法识别方法&#39; System.String get_Item(的Int32)&#39;方法,这个方法无法翻译成一个 商店表达。
据我所知,我无法访问Linq中的[]到Sql查询。你能否提出一个替代方案或指出我正确的方向?
编辑:
关于我想解决的问题的更多细节:
dict有15-20项,键保持不变,只有值动态变化
我试图根据r.Id的范围来排序问题,即如果floor(r.Id)== 14那么我返回&#34; a&#34;如果它在楼层之间(r.Id)== 15那么我返回&#34; b&#34;如果它在floor(r.id)== 13之间,我返回&#34; c&#34;(由dict中的值决定)这有助于排序行
这是实际的表达方式:
List<int> cqh;
List<int> iqh;
Expression<Func<DbQuestion, 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();
谢谢,
答案 0 :(得分:3)
我看到两个选项,与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
以上方法)。在这种情况下,它实际上可能表现更好