C# 如何将反射与LINQ一起用于实体以获取实体属性的值?

C# 如何将反射与LINQ一起用于实体以获取实体属性的值?,c#,linq,entity-framework,reflection,C#,Linq,Entity Framework,Reflection,我尝试执行以下语句: int count = this.objectReportsRepository.All() .Count(or => (int)or.GetPropertyValue("ReportingUserId") == reportModel.ReportingUserId && or.GetPropertyValue("Reported" + target + "Id") == reportModel.Get

我尝试执行以下语句:

int count = this.objectReportsRepository.All()
            .Count(or => (int)or.GetPropertyValue("ReportingUserId") == reportModel.ReportingUserId
            && or.GetPropertyValue("Reported" + target + "Id") == reportModel.GetPropertyValue("Reported" + target + "Id")
            && DbFunctions.TruncateTime((DateTime)or.GetPropertyValue("ReportDate")) == serverTimeToday);
但是,我得到一个错误: System.NotSupportedException:LINQ to Entities无法识别方法“System.Object GetPropertyValue[QuestionReport]解释器mdal.QuestionReport,System.String”,并且无法将此方法转换为存储表达式

var or = Expression.Parameter(typeof(ObjectReport));
var cond1 = Expression.Equal(
    Expression.Property(or, "ReportingUserId"), 
    Expression.Constant(reportModel.ReportingUserId));
var cond2 = Expression.Equal(
    Expression.Property(or, "Reported" + target + "Id"), 
    Expression.Constant(reportModel.GetPropertyValue("Reported" + target + "Id")));
var cond3 = Expression.Equal(
    Expression.Call(
        typeof(DbFunctions), 
        "TruncateTime", 
        Type.EmptyTypes, 
        Expression.Convert(Expression.Property(or, "ReportDate"), typeof(DateTime?))),
    Expression.Convert(Expression.Constant(serverTimeToday), typeof(DateTime?)));
var cond = Expression.AndAlso(Expression.AndAlso(cond1, cond2), cond3);
var predicate = Expression.Lambda<Func<ObjectReport, bool>>(cond, or);

int count = this.objectReportsRepository.All().Count(predicate);
GetPropertyValue实际上是我自己编写的使用反射的扩展方法:

public static object GetPropertyValue<T>(this T sourceObject, string propertyName)
{
    return sourceObject.GetType().GetProperty(propertyName).GetValue(sourceObject, null);
}
我想执行写在问题顶部的LINQ to Entities语句,因为我有不同的报表实体。例如,我有QuestionReport、UserReport、TagReport等实体。我对它们也这么做,但它们有不同的含义。QuestionReport实体存储问题实体的报告。UserReport-用于用户实体等。因此,我不想重复写相同的代码n次,而是想进行用户反射

我唯一能想到的是在All方法调用之后添加一个ToList方法调用,但是通过这样做,我实际上加载了内存中的所有实体,并且只有在这之后,我才计算我想要计算的东西,而不是用一个简单的查询来计算它


帮忙?有人吗

您需要构建表达式树,以便对linq to实体使用它,请尝试此表达式

var or = Expression.Parameter(typeof(ObjectReport));
var cond1 = Expression.Equal(
    Expression.Property(or, "ReportingUserId"), 
    Expression.Constant(reportModel.ReportingUserId));
var cond2 = Expression.Equal(
    Expression.Property(or, "Reported" + target + "Id"), 
    Expression.Constant(reportModel.GetPropertyValue("Reported" + target + "Id")));
var cond3 = Expression.Equal(
    Expression.Call(
        typeof(DbFunctions), 
        "TruncateTime", 
        Type.EmptyTypes, 
        Expression.Convert(Expression.Property(or, "ReportDate"), typeof(DateTime?))),
    Expression.Convert(Expression.Constant(serverTimeToday), typeof(DateTime?)));
var cond = Expression.AndAlso(Expression.AndAlso(cond1, cond2), cond3);
var predicate = Expression.Lambda<Func<ObjectReport, bool>>(cond, or);

int count = this.objectReportsRepository.All().Count(predicate);

无意冒犯,伙计,如果你要像这样滥用泛型,为什么还要使用实体框架呢

您的存储库应该是一个存储库,以便在执行时,您只需通过Func直接选择所需的属性值即可。然后在您的代码中,无论您在哪里需要一个存储库,一切都是自动设置的,您的查询可以简单地执行

var questions = repository.All(questionReport => questionReport.Question == "How old are you");
在任何类型的循环中都不应该使用反射。效率很低


不管怎么说,如果您仍然设置了这个选项,那么您必须先执行.All.ToList,然后再次循环它来执行您的逻辑,因为要重新执行:您的操作非常非常错误。

如果您想在查询中执行C代码,那么您必须先将所有数据提取到内存中,EF无法将扩展方法转换为SQL。+1为此,你使用反射的方式开始变成一种代码气味,你应该考虑其他的选择。我也想说,我不是试图粗鲁或任何事。我不确定你是否误解了我的问题,或者我是否做错了。我不是想粗鲁,我真的不确定。My All方法返回实体集。我的意思是,有了上面的例子,我有一个存储库,它的All方法实际上返回一个IQueryable。当我想执行你写的语句时,我只需要执行repository.All.Whereqr=>qr.Question=你多大了?;那么,为什么这是错误的,它与您编写的代码有什么不同呢?我想再次理解,这不是粗鲁的行为?好吧,但是为什么您要使用反射来获取您的属性呢?如果不返回匿名类型(顺序为{etc}.Countor=>or.ReportingUserID==reportModel.ReportingUserID&&{etc}),则count函数调用应该简单得多。如果要检索实际的类型,根本不需要使用反射。我想我知道你现在想做什么了,但这太过工程化了。除非您可以让所有3个数据模型类都从具有您要查找的属性的接口继承,否则我不会走这条路。反思不是一个好主意。