我们需要以动态方式构建EF表达式。例如,创建测试模型:
public class TestBase
{
public int Id { get; set; }
}
public class TestCard : TestBase
{
public Guid Guid { get; set; }
}
创建一个linq查询:
var q = from card in Context.hlt_disp_Card
select new TestCard
{
Id = card.disp_CardID,
Guid = card.Guid
};
正常使用表达式:
Expression<Func<TestCard, bool>> ex1 = card => card.Id == 1030;
q.Where(ex1).ToList();
我们需要从任何类型创建表达式,并且我们总是有一个字符串名称属性,因此我们尝试以这种方式构造它:
var e = Expression.Parameter(typeof(TestCard), "card");
Expression bin = Expression.Property(e, "Id");
bin = Expression.Equal(bin, Expression.Constant(1030));
var ex2 = Expression.Lambda<Func<TestCard, bool>>(bin, e);
q.Where(ex2).ToList();
但我们收到了警告:
Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory [8] LINQ表达式'(new TestCard(){Id = [card] .disp_CardID,Guid = [card] .Guid} .Id == 1030)'无法翻译,将会 在当地评估。要配置此警告,请使用 DbContextOptionsBuilder.ConfigureWarnings API(事件ID 'RelationalEventId.QueryClientEvaluationWarning')。 ConfigureWarnings 可以在重写DbContext.OnConfiguring方法时使用 在应用程序服务提供程序上使用AddDbContext。
我们在探查器中检查了结果SQL并得到了以下结果: q.Where(EX1).ToList();
SELECT [card].[disp_CardID], [card].[Guid]
FROM [hlt_disp_Card] AS [card]
WHERE [card].[disp_CardID] = 1030
和q.Where(ex2).ToList();
SELECT [card].[disp_CardID], [card].[Guid]
FROM [hlt_disp_Card] AS [card]
如果我尝试为 not-inherited 属性构建过滤器(例如Guid),我的方式很有效!
EF Core版本:1.0.1
如何解决这个问题?
答案 0 :(得分:2)
两个表达式之间的唯一区别是属性访问器表达式ReflectedType
的Member
。
您可以这样修复:
// ...
var p = e.Type.GetProperty("Id");
if (p.ReflectedType != p.DeclaringType)
p = p.DeclaringType.GetProperty(p.Name);
Expression bin = Expression.MakeMemberAccess(e, p);
// ...
但有这样的要求很奇怪,我建议将问题报告给EF Core GitHub。