如果继承,有条件地在非EDM基类型中定义的属性上添加查询运算符

时间:2015-08-10 00:46:43

标签: entity-framework generics inheritance

(问题末尾的C#代码)

我有以下继承链:

abcdef Merged branch 'feature/1234' into branch 'master'

PreRecord <- Record <- (multiple entity types) 声明属性Record

ID As IntegerPreRecord不是EDM类型,并且与数据库中的表不对应。

我有一个方法,它将泛型参数约束为Record,并使用泛型参数作为元素类型构建EF查询。在运行时,如果PreRecord不仅继承自T而是继承自PreRecord,我希望在Record上添加OrderBy运算符:

ID

如果参数约束是'Sample 1 Function GetQuery(Of T As PreRecord)(row As T) As IQueryable(Of T) Dim dcx = New MyDbContext Dim qry = dcx.Set(Of T).AsQueryable If TypeOf row Is RecordBase Then 'modify/rewrite the query here End If Return qry End Function ,那么应用使用Record属性的查询运算符会没有问题。如何在中间方法中使用不同的(缩小的)通用约束并仍然返回ID / IQueryable(Of T),其中IQueryable<T>仍然被约束为T

我试过了:

PreRecord

不起作用:

  

LINQ to Entities仅支持转换EDM原语或枚举类型。

C#等价物:

'Sample 2
qry = dcx.Set(Of T).Cast(Of Record).OrderBy(Function(x) x.ID).Cast(Of PreRecord)()

这不起作用:

//Sample 1
public IQueryable<T> GetQuery<T>(T row) where T : PreRecord {
    var dcx = new MyDbContext();
    var qry = dcx.Set<T>.AsQueryable();
    if (row is RecordBase) {
        //modify/rewrite the query here
    }
    return qry;
}

1 个答案:

答案 0 :(得分:2)

这里的问题是编译器在编译时检查了查询,而PreRecord类没有ID属性。我们不能简单地使用Cast,因为当它用于定义查询时,解析器会尝试将其转换为sql - 但是sql中不存在这样的东西。 Sql仅支持将一种列类型转换为另一种列类型 - 因此在.NET端,它仅支持原始类型和枚举类型。为了克服编译器查询检查,我们可以使用Expression类来构建动态查询:

ParameterExpression e = Expression.Parameter(typeof(Record));
Expression body = Expression.Property(e, "ID");
Expression<Func<PreRecord, int>> orderByExpression = Expression.Lambda<Func<PreRecord, int>>(body, e);

在查询中使用您的表达式:

qry = dcx.Set<T>.OrderBy(orderByExpression);

这样,您的linq查询将不会在编译期间验证,而是在执行时验证。这里我假设ID是int类型,如果类型不同,则相应地改变它。