0

Я создаю фреймворк, который позволяет веб-разработчикам создавать страницы CRUD без необходимости проходить через повторяющиеся шаги.Как определить параметры типа из моего кода, который использует DynamicMethod и Entity Framework?

С этой целью я хочу предоставить методы «по умолчанию», которые выполняют такие функции, как сортировка, фильтрация и т. П. Разработчик, использующий мою инфраструктуру, может предоставить свой собственный метод, если он захочет, но должен быть метод по умолчанию, который работает во многих случаях.

Для меня особенно важно, чтобы это было совместимо с Entity Framework.

Я успешно реализовал функцию фильтрации по умолчанию, используя класс DynamicMethod, который позволяет «генерировать» фильтрацию ключом поиска на произвольных классах, сгенерированных Entity Framework.

Я пытаюсь сделать что-то подобное с сортировкой, но у меня проблема. Метод OrderBy принимает два типа параметров, первым из которых является тип сущности, а второй - тип ключа. Этот введенный ключ должен соответствовать типу столбца, который пользователь хочет сортировать, и для того, чтобы это работало со всеми классами сущностей, тип должен определяться во время выполнения.

Я использовал отражение, чтобы обнаружить тип столбца, но я не знаю, как отличить функцию «сравнения» с соответствующим типом Func <>. Поэтому я установил оператор switch, который включает тип. Я хочу избавиться от оператора switch и разделить тип ключа.

Как это сделать? Мой код следует ниже:

public override IEnumerable<T> GetSortedRecords<T>(IEnumerable<T> filteredRecords) 
    { 
     // The goal here is to allow for a developer to provide a method for sorting records, 
     // but to also provide a default method that will work with all instances of EntityObject. 
     // To that end, I believe it is necessary to use the fun fun DynamicMethod object. 

     // Note - check for ASC vs DESC 

     if (NumberOfSorts == 0) 
      return filteredRecords; 

     IOrderedEnumerable<T> sortedRecords = null; 
     for (int i = 0; i < NumberOfSorts; i++) 
     { 
      string propertyName = PropertyNames[ColumnSortOrder[i]]; 
      PropertyInfo property = typeof(T).GetProperties().Single(p => p.Name == propertyName);                 

      switch (property.PropertyType.Name) 
      { 
       // I want to get rid of these branches. 
       case "Int32": 
        Func<T, int> comparerInt32 = GetDefaultKeySelectorForProperty<T, Int32>(property); 
        sortedRecords = i == 0 ? 
        filteredRecords.OrderBy<T, int>(comparerInt32) : 
        sortedRecords.ThenBy<T, int>(comparerInt32); 
        break; 
       case "String": 
        Func<T, string> comparerString = GetDefaultKeySelectorForProperty<T, string>(property); 
        sortedRecords = i == 0 ? 
        filteredRecords.OrderBy<T, string>(comparerString) : 
        sortedRecords.ThenBy<T, string>(comparerString); 
        break; 
       default: 
        throw new NotImplementedException(); 
      }          
     } 
     return sortedRecords;       
    } 

    delegate TKey GetDefaultKeySelectorForPropertyDelegate<T, TKey>(T t); 
    public Func<T, TKey> GetDefaultKeySelectorForProperty<T, TKey>(PropertyInfo property) 
    { 
     DynamicMethod method = new DynamicMethod("GetKeySelector", typeof(TKey), new Type[] { typeof(T) }); 
     ILGenerator generator = method.GetILGenerator(); 

     MethodInfo GetPropertyValue = property.GetGetMethod(); 
     generator.Emit(OpCodes.Ldarg_0); 
     generator.Emit(OpCodes.Callvirt, GetPropertyValue); 
     generator.Emit(OpCodes.Ret); 

     return ((GetDefaultKeySelectorForPropertyDelegate<T, TKey>)(method.CreateDelegate(typeof(GetDefaultKeySelectorForPropertyDelegate<T, TKey>)))).Invoke; 
    } 
+0

Вы можете, как [этот] (http://stackoverflow.com/q/41244/861716). –

ответ

0

Если вы хотите сделать действительно динамические вызовы, где сайт Вызывающего также имеет дело с полями временем выполнения, то Есть 2 основных подхода к динамическим выражениям и запросам в LINQ.

а) Строка Динамические Lambda

System.Linq.Dynamic можно найти по следующим ссылкам

http://msdn.microsoft.com/en-US/vstudio/bb894665.aspx

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

http://www.scottgu.com/blogposts/dynquery/dynamiclinqcsharp.zip

б) Строительства Деревья выражений

Более мощный, но сложнее освоить ... Строить выражения деревьев с кодом здесь: http://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx

Однако, если вам нужно только Resposityory шаблон родовое и сайт вызывающий будет знать, может поставить предикаты то что-то как это.

/// <summary> 
    /// The sorted page list is the main way of retrieving a subset of data. 
    /// </summary> 
    /// <typeparam name="TSortKey"></typeparam> 
    /// <param name="predicate"></param> 
    /// <param name="sortBy"></param> 
    /// <param name="descending"></param> 
    /// <param name="skipRecords"></param> 
    /// <param name="takeRecords"></param> 
    /// <returns></returns> 
    public virtual IQueryable<TPoco> GetSortedPageList<TSortKey>(Expression<Func<TPoco, bool>> predicate, 
            Expression<Func<TPoco, TSortKey>> sortBy, bool descending, int skipRecords, int takeRecords) { 
     if (!descending) { 
      return Context.Set<TPoco>().Where<TPoco>(predicate) 
        .OrderBy(sortBy) 
        .Skip(skipRecords) 
        .Take(takeRecords); 
     } 
     return 
      Context.Set<TPoco>().Where<TPoco>(predicate) 
       .OrderByDescending(sortBy) 
       .Skip(skipRecords) 
       .Take(takeRecords); 
    } 

ОБРАЗЦА ВЫЗОВ

[TestMethod] 
    public void BaseRepositoryPagingTest() { 
     var luw = new LuwMaster(); 

     var someMore = true; 
     var skip = 0; 
     var take = 3; 

     while (someMore) { 
      var mimeList = luw.GetRepository<MimeType>().GetSortedPageList(m => true, m => m.Id, true, skip, take); 
      someMore = false; 
      foreach (var mimeType in mimeList) { 
       Debug.WriteLine(mimeType.MimeTypeCategory + ", " + mimeType.Id); 
       someMore = true; 
      } 
      skip = skip + take; 
     } 
    }