如何使用反射和LINQ to Entities来获取实体属性的值?

时间:2014-10-01 13:24:35

标签: c# linq entity-framework reflection

我尝试执行以下语句:

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](InterpretumDAL.QuestionReport,System.String)'方法,此方法无法转换为商店表达式。

GetPropertyValue 实际上是我自己编写的使用反射的扩展方法:

public static object GetPropertyValue<T>(this T sourceObject, string propertyName)
{
    return sourceObject.GetType().GetProperty(propertyName).GetValue(sourceObject, null);
}

我想执行写在我问题顶部的LINQ to Entities语句,因为我有不同的Report实体。例如,我有QuestionReport,UserReport,TagReport等实体。我对他们做了同样的事,但他们有不同的含义。 QuestionReport实体存储Question实体的报告。 UserReport - 用于用户实体等。因此,我想要用户反射,而不是写相同的代码 n

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

帮助?任何人? :)

2 个答案:

答案 0 :(得分:3)

你需要构建表达式树,以便将它用于linq到实体,试试这个表达式。

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);

答案 1 :(得分:1)

没有冒犯男人,但如果你要滥用这样的仿制品,为什么甚至使用实体框架呢?

您的存储库应该是Repository<T>,这样当您执行.All()时,您可以直接通过Func选择所需的属性值。然后在您的代码中,只要您需要Repository<QuestionReport>,一切都会自动设置,您的查询就可以轻松执行

var questions = repository.All(questionReport => questionReport.Question == "How old are you");

你应该从不在任何类型的循环中使用反射。这是非常低效的。

无论如何,如果你仍然设置了这个,你将不得不做.All()。ToList()然后再循环它来做你的逻辑,因为(重写):你正在做非常非常错误。