2009-07-17 11 views
23

का समर्थन करने का समर्थन करती हैं मैंने ऑर्डरबी क्लॉज के लिए अभिव्यक्ति को पारित करने की अनुमति देने के लिए एक विधि लिखी है, लेकिन मैं इस समस्या में भाग गया।इकाई फ्रेमवर्क: LINQ से इकाइयां केवल कास्टिंग एंटीटी डेटा मॉडल आदिम प्रकार

प्रकार 'System.DateTime' टाइप करने के लिए 'System.IComparable' कास्ट करने में असमर्थ। LINQ से इकाइयों केवल कास्टिंग इकाई डेटा मॉडल आदिम प्रकार का समर्थन करता है।

मूल रूप से अभिव्यक्ति यह है:

Expression<Func<K, IComparable>> orderBy 

और इस तरह प्रयोग किया जाता है:

SomeEntities.SomeTable 
.Where 
(
    whereClause 
) 
.Select 
(
    selectClause 
) 
.OrderBy(orderBy) 

विचार है, ताकि मैं एक शब्दकोश का उपयोग कर सकते स्ट्रिंग की तरह भाव मैचों धारण करने के लिए:

_possibleSortForForumItem.Add("CreateDate", item => item.CreateDate); 

तो मैं एक विधि है कि लगता है सॉर्ट स्ट्रिंग में और अभिव्यक्ति देता है अगर यह शब्दकोश में एक कुंजी से मेल खाता है, अगर कुछ डिफ़ॉल्ट नहीं देता है। (विचार यह नियंत्रित करने का एक तरीका है कि इसे किस क्रम में आदेश दिया जा सकता है) अब यह स्ट्रिंग गुणों के लिए काम करता है, लेकिन अब तक डेटाटाइम या पूर्णांक के लिए नहीं है क्योंकि मुझे उपरोक्त त्रुटि संदेश मिलता है।

अब तक जब तक मैं समस्या को समझता हूं, यह है कि इकाई फ्रेमवर्क को प्राथमिक/ईडीएम प्रकार होने की आवश्यकता होती है क्योंकि इसे सी # डेटटाइम को डेटाबेस को संभालने में कुछ बदलना पड़ता है।

क्या डेटाटाइम को एक आदिम प्रकार में बदलने का कोई तरीका है ताकि यह अभी भी काम करेगा?

समाधान

विधि द्वारा आदेश प्राप्त करने के लिए विधि: (एक प्रश्न में ले लो और "का आदेश दिया रूप" में इसे वापस)

private static Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>> GetMethodForSort(String sortBy) 
{ 
    if (_methodForSort == null) 
    { 
    _methodForSort = new Dictionary<String, Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>>>(); 
    _methodForSort.Add(SortForumViewItemCreatedOn, item => item.OrderBy(innerItem => innerItem.CreatedOn)); 
    ... 
    } 

    Func<IQueryable<ForumViewItem>, IOrderedQueryable<ForumViewItem>> orderMethod; 

    if(String.IsNullOrEmpty(sortBy) || !_methodForSort.ContainsKey(sortBy)) 
    { 
    orderMethod = _methodForSort["ForumName"]; 
    } 
    else 
    { 
    orderMethod = _methodForSort[sortBy]; 
    } 

    return orderMethod; 
} 

व्यापक क्वेरी विधि हस्ताक्षर विधि:

IList<K> GetListForGrid<T, K>(this ObjectQuery<T> query, ... Func<IQueryable<K>, IOrderedQueryable<K>> orderBy, ...) 

और विधि में पारित के उपयोग:

+०१२३५१६४१०६१
initialQuery = query 
    .Where 
    (
    somethingEqualsSomething 
) 
    .Select 
    (
    selectClause 
); 

var orderedQuery = orderBy(initialQuery); 

returnValue = orderedQuery 
    .Skip(numberToShow * realPage) 
    .Take(numberToShow) 
    .ToList(); 

उत्तर

12

इकाई फ्रेमवर्क यह कठिन बनाता है और मुझे यकीन नहीं है कि आप एक ही वापसी मूल्य प्रकार (आईसीओपरपेबल, ऑब्जेक्ट इत्यादि) के साथ क्या करना चाहते हैं, ऐसा करने का एक तरीका है। इसलिए तरह इसे लागू करने

_possibleSortForForumItem.Add("CreateDate", 
    query => query.OrderBy(item.CreateDate)); 

और फिर:: आप नाम-हैं- Func<IQueryable<K>, IOrderedQueryable<K>> मूल्यों की एक शब्दकोश में अपने डिजाइन दोबारा काम पर विचार हो सकता

var orderedQuery = query.OrderBy(item => item.DefaultOrderColumn); 

Func<IQueryable<K>, IOrderedQueryable<K>> assignOrderBy = null; 

if (_possibleSortForForumItem.TryGetValue(orderColumnName, out assignOrderBy)) 
{ 
    orderedQuery = assignOrderBy(query); 
} 
+0

मैं Func के परिणामस्वरूप IOrderedQueryable का सुझाव दूंगा, यह संकलन समय पर लागू होगा ऑर्डरबी का उपयोग किया जाता है, क्योंकि उदाहरण के लिए पेजिंग को ऑर्डर किए गए प्रश्न पसंद नहीं हैं। –

+0

डेवी, सहमत। मैंने इसे प्रतिबिंबित करने के लिए कोड बदल दिया। –

+0

मुझे यह जानने के लिए कुछ मिनट लग गए कि अंत में यह कैसे कामयाब है, लेकिन अंत में यह बहुत ही व्यावहारिक है। –

21

मैं जानता हूँ कि यह पुराना है, लेकिन मुझे लगता है पूरा करने के लिए देख रहा था ओपी के समान सटीक बात और मेरे शब्दकोश में Func<IQueryable<T>, IOrderedQueryable<T>> का उपयोग नहीं करना चाहता था। अधिकतर क्योंकि मुझे OrderBy और OrderByDescending प्रतिनिधि दोनों को लागू करना होगा।

मैं एक विस्तार विधि IQueryable ObjectSort जो केवल जाँच करेगा बुलाया के लिए क्या अभिव्यक्ति की वापसी प्रकार होना चाहिए देखने के लिए और उसके बाद तो यह है कि LINQ करने के लिए संस्थाओं बाहर बेकार नहीं जाएगा कि प्रकार का उपयोग कर एक नया लैम्ब्डा बनाने बना दी।

मुझे यकीन नहीं है कि यह एक अच्छा समाधान है या नहीं, लेकिन नीचे दिया गया उदाहरण DateTime और int के लिए काम करता है, इसलिए उम्मीद है कि अगर आप कुछ ऐसा करने की सोच रहे हैं तो यह आपको कुछ विचार दे सकता है!

public static IOrderedQueryable<T> ObjectSort<T>(this IQueryable<T> entities, Expression<Func<T, object>> expression, SortOrder order = SortOrder.Ascending) 
{ 
    var unaryExpression = expression.Body as UnaryExpression; 
    if (unaryExpression != null) 
    { 
     var propertyExpression = (MemberExpression)unaryExpression.Operand; 
     var parameters = expression.Parameters; 

     if (propertyExpression.Type == typeof(DateTime)) 
     { 
      var newExpression = Expression.Lambda<Func<T, DateTime>>(propertyExpression, parameters); 
      return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression); 
     } 

     if (propertyExpression.Type == typeof(int)) 
     { 
      var newExpression = Expression.Lambda<Func<T, int>>(propertyExpression, parameters); 
      return order == SortOrder.Ascending ? entities.OrderBy(newExpression) : entities.OrderByDescending(newExpression); 
     } 

     throw new NotSupportedException("Object type resolution not implemented for this type"); 
    } 
    return entities.OrderBy(expression); 
} 
+3

इस महान विस्तार के लिए धन्यवाद! फिर भी यह स्ट्रिंग कॉलम को सही तरीके से सॉर्ट नहीं करता है। मैंने अंतिम पंक्ति को बदलकर इसे ठीक किया: 'वापसी आदेश == SortOrder.Acending?entities.OrderBy (अभिव्यक्ति): इकाइयों। ऑर्डर बाईडिस्केंडिंग (अभिव्यक्ति); ' – SoftwareFactor

4

मूल पोस्टर, जहां के रूप में एक ऐसी ही समस्या आई भाव जहां प्रकार अभिव्यक्ति < समारोह < टी की lambdas के रूप में लिखा, वस्तु > > "आदेश दिया गया"। इन्हें एनएचबीर्नेट लिनक प्रदाता द्वारा सही ढंग से व्याख्या किया गया था, लेकिन ईएफ 5 में माइग्रेट करने के परिणामस्वरूप "System.icomparable 'टाइप करने के लिए" System.DateTime' टाइप करने में असमर्थ हुआ। LINQ से Entities केवल एंटिटी डेटा मॉडल आदिम प्रकार कास्टिंग का समर्थन करता है। "

निम्न विधियों में अभिव्यक्ति < समारोह < टी करने के लिए एक रूपांतरण, TKey > > प्रदान जब विभिन्न "OrderBy" तरीकों बुला (प्रतिबिंब का उपयोग कर - क्षमा याचना ...) नोट वे मूल रूप से एक सामान्य वर्ग > में OrderBy < टी समझाया गया ।

private static readonly Type QueryableType = typeof(Queryable); 

    // HACK: Use reflection to call strongly-typed methods instead of object-based methods 
    // This is to work around "Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types." 
    private IOrderedQueryable<T> ApplyOrderByTo(
     IQueryable<T> query, 
     Expression<Func<T, object>> keySelector, 
     bool sortAscending, 
     bool useReflection) 
    { 
     if (useReflection) 
     { 
      var body = keySelector.Body as UnaryExpression; 
      var keyExpr = body.Operand as MemberExpression; 

      return (IOrderedQueryable<T>)query.Provider.CreateQuery(
       Expression.Call(
       QueryableType, 
       sortAscending ? "OrderBy" : "OrderByDescending", 
       new Type[] { typeof(T), keyExpr.Type }, 
       query.Expression, 
       Expression.Lambda(keyExpr, keySelector.Parameters))); 
     } 
     else 
     { 
      if (sortAscending) 
       return query.OrderBy(keySelector); 
      else 
       return query.OrderByDescending(keySelector); 
     } 
    } 

    // HACK: Use reflection to call strongly-typed methods instead of object-based methods 
    // This is to work around "Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types." 
    private IOrderedQueryable<T> ApplyOrderByTo(
     IOrderedQueryable<T> query, 
     Expression<Func<T, object>> keySelector, 
     bool sortAscending, 
     bool useReflection) 
    { 
     if (useReflection) 
     { 
      var body = keySelector.Body as UnaryExpression; 
      var keyExpr = body.Operand as MemberExpression; 

      return (IOrderedQueryable<T>)query.Provider.CreateQuery(
       Expression.Call(
       QueryableType, 
       sortAscending ? "ThenBy" : "ThenByDescending", 
       new Type[] { typeof(T), keyExpr.Type }, 
       query.Expression, 
       Expression.Lambda(keyExpr, keySelector.Parameters))); 
     } 
     else 
     { 
      if (sortAscending) 
       return query.ThenBy(keySelector); 
      else 
       return query.ThenByDescending(keySelector); 
     } 
    } 
0

ओल्डनिक से प्रेरणा के साथ मैंने सदस्यों द्वारा सॉर्ट करने के लिए कुछ एक्सटेंशन विधियां बनाईं। यह मेरे लिए बहुत अच्छा काम करता है। मैं सॉर्ट ऑर्डर को परिभाषित करने के लिए System.Data.SqlClient.SortOrder enum का भी उपयोग कर रहा हूं।

 /// <summary> 
    ///  Supports sorting of a given member as an expression when type is not known. It solves problem with LINQ to Entities unable to 
    ///  cast different types as 'System.DateTime', 'System.DateTime?' to type 'System.Object'. 
    ///  LINQ to Entities only supports casting Entity Data Model primitive types. 
    /// </summary> 
    /// <typeparam name="T">entity type</typeparam> 
    /// <param name="query">query to apply sorting on.</param> 
    /// <param name="expression">the member expression to apply</param> 
    /// <param name="sortOrder">the sort order to apply</param> 
    /// <returns>Query with sorting applied as IOrderedQueryable of type T</returns> 
    public static IOrderedQueryable<T> OrderByMember<T>(
     this IQueryable<T> query, 
     Expression<Func<T, object>> expression, 
     SortOrder sortOrder) 
    { 
     var body = expression.Body as UnaryExpression; 

     if (body != null) 
     { 
      var memberExpression = body.Operand as MemberExpression; 

      if (memberExpression != null) 
      { 
       return 
        (IOrderedQueryable<T>) 
        query.Provider.CreateQuery(
         Expression.Call(
          typeof(Queryable), 
          sortOrder == SortOrder.Ascending ? "OrderBy" : "OrderByDescending", 
          new[] { typeof(T), memberExpression.Type }, 
          query.Expression, 
          Expression.Lambda(memberExpression, expression.Parameters))); 
      } 
     } 

     return sortOrder == SortOrder.Ascending ? query.OrderBy(expression) : query.OrderByDescending(expression); 
    } 

    /// <summary> 
    ///  Supports sorting of a given member as an expression when type is not known. It solves problem with LINQ to Entities unable to 
    ///  cast different types as 'System.DateTime', 'System.DateTime?' to type 'System.Object'. 
    ///  LINQ to Entities only supports casting Entity Data Model primitive types. 
    /// </summary> 
    /// <typeparam name="T">entity type</typeparam> 
    /// <param name="query">query to apply sorting on.</param> 
    /// <param name="expression">the member expression to apply</param> 
    /// <param name="sortOrder">the sort order to apply</param> 
    /// <returns>Query with sorting applied as IOrderedQueryable of type T</returns> 
    public static IOrderedQueryable<T> ThenByMember<T>(
     this IQueryable<T> query, 
     Expression<Func<T, object>> expression, 
     SortOrder sortOrder) 
    { 
     return ((IOrderedQueryable<T>)query).ThenByMember(expression, sortOrder); 
    } 

    /// <summary> 
    ///  Supports sorting of a given member as an expression when type is not known. It solves problem with LINQ to Entities unable to 
    ///  cast different types as 'System.DateTime', 'System.DateTime?' to type 'System.Object'. 
    ///  LINQ to Entities only supports casting Entity Data Model primitive types. 
    /// </summary> 
    /// <typeparam name="T">entity type</typeparam> 
    /// <param name="query">query to apply sorting on.</param> 
    /// <param name="expression">the member expression to apply</param> 
    /// <param name="sortOrder">the sort order to apply</param> 
    /// <returns>Query with sorting applied as IOrderedQueryable of type T</returns> 
    public static IOrderedQueryable<T> ThenByMember<T>(
     this IOrderedQueryable<T> query, 
     Expression<Func<T, object>> expression, 
     SortOrder sortOrder) 
    { 
     var body = expression.Body as UnaryExpression; 

     if (body != null) 
     { 
      var memberExpression = body.Operand as MemberExpression; 

      if (memberExpression != null) 
      { 
       return 
        (IOrderedQueryable<T>) 
        query.Provider.CreateQuery(
         Expression.Call(
          typeof(Queryable), 
          sortOrder == SortOrder.Ascending ? "ThenBy" : "ThenByDescending", 
          new[] { typeof(T), memberExpression.Type }, 
          query.Expression, 
          Expression.Lambda(memberExpression, expression.Parameters))); 
      } 
     } 

     return sortOrder == SortOrder.Ascending ? query.ThenBy(expression) : query.ThenByDescending(expression); 
    } 
2

मुझे आपकी समस्या का बहुत आसान समाधान मिला (और मेरा भी)।

Expression<Func<TObject, DateTime>> Expr = obj=>obj.StartDate; 
dynamic dynExpr=Expr; 

अब आप एक तालिका में dynExpr की दुकान या कहीं भी आप चाहते हैं कर सकते हैं, एक साथ पूर्णांक के साथ: जब आप अपने खोज अभिव्यक्ति बनाते हैं, आप से अधिक संपत्ति के प्रकार (आप यह तो जानते हैं), लेकिन दुकान अभिव्यक्ति गतिशील चर में पास करना चाहिए अभिव्यक्ति, स्ट्रिंग एक्सप्रेशन, ... और जब समय आ गया है तो आप इसे ऑर्डरबी विधि में उपयोग कर सकते हैं। लेकिन नहीं मानक तरीके से (विस्तार विधि):

query=query.OrderBy(dynExpr); 

, केवल इस तरह से:

query=Queryable.OrderBy(query, dynExpr); 

इस तरह आप सभी छँटाई कार्य (OrderBy, OrderByDescending, ThenBy, ThenByDescending) में एक अभिव्यक्ति का उपयोग कर सकते हैं ।

+0

यह मेरी समस्या को हल करता है, क्योंकि मैं गतिशील रूप से कई अलग-अलग डेटा प्रकारों के साथ खोज पूर्वानुमान और कॉलम ऑर्डरिंग बनाना चाहता हूं। – sovemp

संबंधित मुद्दे