![](/img/trans.png)
[英]How to prevent Convert in generated expression for type parameter is interface
[英]Expression generated based on interface
我收到異常無法將類型“MySomeTypeThatImplementsISomeInterfaceAndIsPassedAs[T]ToTheClass”轉換為類型“ISomeInterface”。 LINQ to Entities 僅支持強制轉換實體數據模型基元類型。
我的存儲庫看起來像
public interface IRepository<T>
{
IQueryable<T> Get(System.Linq.Expressions.Expression<System.Func<T, bool>> Query);
}
另外,我有服務類
public abstract class FinanceServiceBase<TAccount, TParcel, TPayment>
where TAccount : IAccount
where TParcel : IParcel
where TPayment : IPayment
{
//...
IRepository<TPayment> ParcelRepository {get; private set;}
public bool MakePayment(TPayment payment)
{
//...
ParcelRepository.Get(p => p.ParcelId == 2);
// here my exception is thrown
// **p.ParcelId is in IParcel**
//...
}
}
//...
有了這門課,我可以控制很多關於財務的事情,而無需為其他程序重寫代碼。 我用 3 個通用參數做了這個類,因為我不能使用 IRepository 因為我的存儲庫不能<out T>
ParcelId 是 Int32
TParcel 是 typeof( ParcelToReceive ),它是一個實現IParcel的實體,並且是用 codeonly 生成的
當我調用 Get 時出現問題,結果 lambda 看起來像
(**(ISomeInterface)**$p).SomeInterfaceMember ==
而不是
($p.SomeInterfaceMember)
因此,實體框架嘗試進行強制轉換並拋出異常。 我想知道的是:無論如何要告訴 linq lambda 字段 p.ParcelId 來自TParcel而不是來自IParcel 。
已經嘗試過(沒有運氣):
p => ((TParcel)p).ParcelId
謝謝
似乎將通用約束從where TAccount : IAccount
為where TAccount : class, IAccount
告訴實體框架表達式包含一個類,並且它不會對原始 EDM 和枚舉類型進行顯式轉換。
恐怕您不能這樣做,因為從根本上說,您正在訪問接口中聲明的屬性。 LINQ-to-Entities 似乎不支持; 您需要在真實實體類型中調用該屬性。
解決此問題的一種方法是將parcelId
屬性作為表達式樹傳遞給參數,然后在運行時使用該參數中的屬性動態構造 lambda 表達式:
public bool MakePayment(TPayment payment,
Expression<Func<TParcel, int>> parcelIdExpr)
{
// You can use any expression involving parcelId here
Expression<Func<int, bool>> expr = parcelId => parcelId == 2;
// This is the parameter of the new lambda we’re creating
var parameter = Expression.Parameter(typeof(TParcel));
// This constructs the lambda expression “p => expr(p.ParcelId)”,
// where “expr” is the lambda expression declared above
var lambda = Expression.Lambda(Expression.Invoke(expr,
Expression.Invoke(parcelIdExpr, parameter)), parameter);
ParcelRepository.Get((Expression<Func<TParcel, bool>>) lambda);
}
[...]
myFinanceService.MakePayment(myPayment, p => p.ParcelId);
如果您不想在每次調用MakePayment
時都傳遞這個額外的參數,那么理論上您可以使用字符串文字按名稱檢索屬性; 然而,這是不安全的,因為它不能確保它是實現接口的正確屬性。 此外,這是一種非常迂回的方式,所以不能保證:
public bool MakePayment(TPayment payment)
{
Expression<Func<int, bool>> expr = parcelId => parcelId == 2;
var parameter = Expression.Parameter(typeof(TParcel));
// This is the expression “p.ParcelId”, where “p” is the parameter
var propertyExpression = Expression.Property(parameter, "ParcelId");
var lambda = Expression.Lambda(Expression.Invoke(expr, propertyExpression),
parameter);
ParcelRepository.Get((Expression<Func<TParcel, bool>>) lambda);
}
您可以將其分解為通用實用程序方法:
public static class Utils
{
public static Expression<Func<TParameter, TResult>>
CombineLambdas<TParameter, T, TResult>(
Expression<Func<TParameter, T>> lambda1,
Expression<Func<T, TResult>> lambda2
)
{
var parameter = Expression.Parameter(typeof(TParameter));
var lambda = Expression.Lambda(Expression.Invoke(lambda2,
Expression.Invoke(lambda1, parameter)), parameter);
return (Expression<Func<TParameter, TResult>>) lambda;
}
}
public bool MakePayment(TPayment payment,
Expression<Func<TParcel, int>> parcelIdExpr)
{
ParcelRepository.Get(Utils.CombineLambdas(
parcelIdExpr, parcelId => parcelId == 2));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.