我正在嘗試以不同的方式實現OrderBy
和ThenBy
,以便從OrderBy
和ThenBy
擴展方法中隱藏lambda表達式。這些擴展方法接受實現IOrderSpecification
類:
public class PersonOrderByAgeSpecification : OrderSpecification<Person>
{
public PersonOrderByAgeSpecification(Sort direction= Sort.Ascending) : base(direction)
{
}
public override Expression<Func<Person, IComparable>> AsExpression()
{
return personOrder => personOrder.Age;
}
}
以及用法:
var orderSpecification = new PersonOrderByAgeSpecification(Sort.Ascending);
var sortedPeople= _dbContext.People.OrderBy(orderSpecification);
當AsExpression()
的屬性類型只是字符串時,它可以正常工作。例如:
public override Expression<Func<Person, IComparable>> AsExpression()
{
return personOrder => personOrder.FirstName;
}
否則,我將收到此錯誤:(不適用於整數或布爾值)
InvalidOperationException:SQL樹中的空TypeMapping
源代碼在這裡
感謝您的幫助。
首先,您使用的是預覽(beta)軟件,該軟件可能會出現問題。
但是主要問題是LINQ排序方法具有第二個泛型類型參數TKey
,您將其隱藏在IComparable
後面,對於值類型,該類型參數會導致表達式內部隱藏轉換。
除了不必要的裝箱外,這對於LINQ to Objects提供程序來說不是問題,因為它只是編譯並執行來自lambda表達式的委託。但是,其他IQueryable
提供程序通常需要將表達式轉換為其他內容(通常是SQL)。它們中的大多數會識別出此類轉換( Expression.Convert
)並在處理期間將其刪除。顯然,您使用的EF 3.0預覽版沒有,因此是個例外。
您可以自己消除隱藏的演員表來避免此類問題。可以通過表達式操作來做到這一點,但是最簡單的方法是在基本抽像類中引入第二個泛型類型參數:
public abstract class OrderSpecification<T, TKey> : IOrderSpecification<T>
並將抽象方法簽名更改為
public abstract Expression<Func<T, TKey>> AsExpression();
實現,接口以及除具體類之外的所有其他內容將保持不變。
現在,您只需要在繼承的類中指定實際的密鑰類型,然後更改AsExpression
覆蓋簽名即可。例如:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class PersonAgeOrderSpecification : OrderSpecification<Person, int>
{
public PersonAgeOrderSpecification(Sort direction) : base(direction) { }
public override Expression<Func<Person, int>> AsExpression()
{
return person => person.Age;
}
}
一切都會好起來的。