0

我正在创建一个框架,旨在允许 Web 开发人员创建 CRUD 页面,而无需通过重复步骤。

为此,我想提供“默认”方法来执行排序、过滤等操作。使用我的框架的开发人员可以选择提供自己的方法,但应该有一个在许多情况下都可以使用的默认方法。

与实体框架兼容对我来说尤其重要。

DynamicMethod我已经使用允许通过搜索键对实体框架生成的任意类进行“通用”过滤的类成功实现了默认过滤功能。

我正在尝试对排序做类似的事情,但我遇到了问题。该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;
    }
4

1 回答 1

0

如果你想做真正的动态调用,调用站点也在处理运行时字段,那么 LINQ 中有两种基本的动态表达式和查询方法。

a)字符串动态 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

b)构建表达式树

更强大但更难掌握......使用此处的代码构建表达式树: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;
        }
    }
于 2013-08-11T18:09:26.790 回答