如何使用反射和LINQ to Entities来获得实体属性';s值

本文关键字:属性 实体 反射 何使用 LINQ to Entities | 更新日期: 2023-09-27 18:25:10

我尝试执行以下语句:

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 Entitys语句,因为我有不同的Report实体。例如,我有QuestionReport、UserReport、TagReport等实体。我对它们做的都是一样的,但它们有不同的含义。QuestionReport实体存储Question实体的报告。UserReport-用于用户实体等等。因此,我不想多次编写相同的代码n,而是希望使用Reflection。

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

帮助?有人吗?:)

如何使用反射和LINQ to Entities来获得实体属性';s值

您需要构建表达式树,以便将其用于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);

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

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

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

您应该永远不要在任何类型的循环中使用反射。这是非常低效的。

无论如何,如果你仍然坚持这一点,你就必须执行.All().ToList(),然后再次循环它来执行你的逻辑,因为(要重新写入):你做得非常非常错误。