2013-10-01 45 views
0

我有一個將linq封裝到sql數據上下文的對象。存儲庫模式和LinqToSql方法

它有一個方法IQuerable<T> FromStore<T>,讓我通過LINQ to SQL中得到相應的表我的實體。

我也有呼通的方法來呼籲數據上下文功能。

我現在的問題是,我不能使用那些通過方法中的WHERE子句,因爲沒有轉換爲SQL。我明白爲什麼會發生這種情況,但我該如何解決它?


示例代碼:

在我的倉庫類:

public class AquaReportsRepository : LinqToSqlRepository<int>, IAquaReportsRepository 
{ 
    public bool IsPhysicalItem(string itemNumber) 
    { 
     return _UnderlyingDataContext.Aqua_IsPhysicalItem(itemNumber) ?? true; 
    } 
} 

試圖從它訪問數據:

from part in Repository.FromStore<Parts>() 
where !(Repository.IsPhysicalItem(part.Item)) // eek, not translation to sql 
select part.ItemNumber; 

在過去,在那裏我」 VE需要一個簡單的屬性的數據對象上,卡從另一個屬性我使用QueryMap將該屬性翻譯成等效表達式,但我不認爲我可以這樣做,因爲我需要訪問datacontext方法。

回答

0

TL; DR:閱讀第1點的示例。使用QueryMap中的代碼,使更改以粗體顯示在下面。


對,我已經成功地解決此使用一些很小的改動就QueryMap

有兩件事情我需要得到工作:

  1. 圖如何告訴querymap調用使用數據上下文的方法?

  2. 圖如何獲得querymap拿起一類,當經由接口被訪問定義的屬性。

第一部分是相當簡單:

private static readonly ExpressionMethod<Func<AquaReportsRepository, string, bool>> _IsPhysicalItem = 
    ExpressionMethod.Create((AquaReportsRepository ardc, string i) => ardc._AquaReportsDC.Aqua_IsPhysicalItem(i) ?? true); 

[MapToExpression("_IsPhysicalItem")] 
public bool IsPhysicalItem(string itemNumber) 
{ 
    return _IsPhysicalItem.Invoke(this, itemNumber); 
} 

這裏的關鍵是,除了簡單地使用一個函數,它的對象本身作爲第一個參數(AquaReportsRepository在這種情況下)正常其他論點。

第二部分然而需要一些(相當輕微)變化爲MappedQueryVisitor.cs。在這兩種情況下只有一個if語句(裏面有語句!)。

替換現有GetLambda方法與此

private LambdaExpression GetLambda(Expression receiver, MemberInfo member) { 

    LambdaExpression exp; 
    if(!_mappings.TryGetValue(member, out exp)) { 
     exp = _mappingLookup(member); 
     if(null == exp) { 
      var attr = (MapToExpressionAttribute) member.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault(); 

      // Added by me to deal with interfaces 
      if (null == attr) 
      { 
       if (null != receiver) 
       { 
        // member could be an interface's member, so check the receiver.object type 
        if (receiver.NodeType == ExpressionType.Constant) 
        { 
         var receiverType = ((ConstantExpression)receiver).Value.GetType(); 

         var receiverMemberInfo = receiverType.GetMembers().Where(mi => mi.Name == member.Name).SingleOrDefault(); 

         if (null != receiverMemberInfo) 
         { 
          attr = (MapToExpressionAttribute)receiverMemberInfo.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault(); 
          member = receiverMemberInfo; 
         } 
        } 
       } 
      } 


      if(null != attr) { 
       exp = GetLambdaFromAttribute(receiver, member.DeclaringType, attr); 
      } 
     } 
     _mappings.Add(member, exp); 
    } 
    return exp; 
} 

這一變化意味着,如果我們有代表的接口方法的memberMethodInfo對象,我們會認識到,和嘗試,並取得了具體的實際MethodInfo我們正在處理的類型(由常量表達式定義)。

現在它正確地在執行類中獲取MapToExpressionAttribute屬性,給定接口的MemberInfo

下一個問題雖然是VisitMethodCall,那裏已經從屬性調用替換表達式,因爲參數表達式是接口類型,所以我們調用的方法需要實現類。

最後一次代碼更改糾正了這種情況。

更改CollectArguments方法來此

private static IEnumerable<Expression> CollectArguments(MethodCallExpression m) { 
    IEnumerable<Expression> args = m.Arguments; 
    if (!m.Method.IsStatic) 
    { 
     var objectExpression = m.Object; 

     // Added by me, to deal with interfaces 
     if (objectExpression.NodeType == ExpressionType.Constant) 
     { 
      var objectConstExpression = ((ConstantExpression)objectExpression); 

      if (objectConstExpression.Type.IsInterface) 
      { 
       objectExpression = Expression.Constant(objectConstExpression.Value); 
      } 
     } 

     args = Enumerable.Repeat(objectExpression, 1).Concat(args); 
    } 
    return args; 
}