2013-02-20 73 views
3

我有一个分层的应用程序用C#编写 -排序依据的N层应用程序中使用DTO时

前端 - (获取的Customers页)

业务 - (CustomerServiceCustomer类)

DataContracts - (CustomerDTO

数据访问 - (UnitOfWorkRepositories

该数据库有一个超过一百个列(许多冗余)的Customer表,因此我使用DTO在业务层上填充Customer对象。在Customer类中,我也更改了其数据库名称中的许多字段的名称,例如ID到客户ID,FName到名字。

前端使用业务层的服务来获取客户,例如, GetAll(), GetByID(int customerID).

我也想要提供像下面这样的GetPaged method

的CustomerService类

public IEnumerable<Customer> GetPaged(
       Func<IQueryable<Customer>, IOrderedQueryable<Customer>> orderBy, 
       int skip, 
       int take) 
{ 
    foreach (var customerDTO in 
        unitOfWork.CustomerRepository.GetPaged(orderBy, skip, take)) 
    { 
      yield return new Customer(customerDTO); 
    } 
} 

但由于CustomerRepository是基于CustomerDTO不是Customer期待的orderBy这是不行的。

我不想让前端知道关于CustomerDTO的任何信息。

我该如何做到这一点?

+2

一个方法得到这个工作将是使用动态OrderBy像[这里](http://stackoverflow.com/questions/41244/dynamic-linq-orderby),所以你可以通过列名参数化排序(字符串),也可以将它们映射到数据层中使用的名称。 – 2013-02-20 19:54:36

+1

我已经尝试了一些方法,似乎是一个静态构造函数填充字典表示映射和翻译方法的字符串是唯一可行的方法。 – tom 2013-02-21 16:39:59

+0

不要这么肯定,看看我更简单的答案。您不需要使用动态OrderBy来使事情更复杂。 – kzfabi 2013-03-05 17:38:19

回答

0

您可以使用可用订单选项公开enum,然后在GetPaged中根据收到的枚举值创建OrderBy。

可能的实现可能是:

public enum OrderCustomersBy 
{ 
    FirstNameAsc, FirstNameDesc, AgeAsc, AgeDesc 
} 

而且在为CustomerService:

private IOrderedQueryable<CustomerDTO> GetOrderBy(OrderCustomersBy orderOption) 
{ 
    IOrderedQueryable<CustomerDTO> orderBy = null; 

    switch (orderOption) 
    { 
     case OrderCustomersBy.FirstNameAsc: 
      // Create order by... 
      break; 
     case OrderCustomersBy.FirstNameDesc: 
      // Create order by... 
      break; 
     case OrderCustomersBy.AgeAsc: 
      // Create order by... 
      break; 
     case OrderCustomersBy.AgeDesc: 
      // Create order by... 
      break; 
     default: 
      throw new NotImplementedException("Order option not implemented: " + orderOption.ToString()); 
    } 

    return orderBy; 
} 

public IEnumerable<Customer> GetPaged(Func<IQueryable<Customer>> func, OrderCustomersBy orderOption, int skip, int take) 
{ 
    IOrderedQueryable<CustomerDTO> orderBy = this.GetOrderBy(orderOption); 

    foreach (var customerDTO in unitOfWork.CustomerRepository.GetPaged(orderBy, skip, take)) 
    { 
     yield return new Customer(customerDTO); 
    } 
} 
0

我看到了两个问题:第一,你怎么了业务实体映射到DTO的;第二,你怎么了在任何列上执行订单?

将业务实体映射到DTO。这可以通过多种方式完成。列举几个:可以使用AutoMapper,可以使用属性进行简单的映射(该属性将包含customDTO或数据库列的属性名称(使用数据库列可能会否定DTO的值)),或者您可以从数据库驱动它,数据库的方法有点沉重和元。

我会按照评论中的建议使用动态排序。是的,它增加了一层抽象,但它减少了维护。

动态排序

public static IQueryable<T> OrderBy<T>(this IQueryable<T> items, string propertyName, SortDirection direction) 
    { 
     var typeOfT = typeof(T); 
     var parameter = Expression.Parameter(typeOfT, "parameter"); 
     var propertyType = typeOfT.GetProperty(propertyName).PropertyType; 
     var propertyAccess = Expression.PropertyOrField(parameter, propertyName); 
     var orderExpression = Expression.Lambda(propertyAccess, parameter); 

     string orderbyMethod = (direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending"); 
     var expression = Expression.Call(typeof(Queryable), orderbyMethod, new[] { typeOfT, propertyType }, items.Expression, Expression.Quote(orderExpression)); 
     return items.Provider.CreateQuery<T>(expression); 
    } 

在当我改变一个实体的一天结束时,我没有兴趣在应用程序中的另一个地方更改代码。

+1

我同意,主要是因为最后一部分。 – kzfabi 2013-03-05 18:36:07

相关问题