订购在N-Tier应用程序中使用DTO时

时间:2013-02-20 19:30:49

标签: c# entity-framework sorting architecture dto

我有一个用C#编写的分层应用程序 -

  

前端 - (获取Customers的页面)

     

商家 - (CustomerServiceCustomer类)

     

DataContracts - (CustomerDTO

     

DataAccess - (UnitOfWorkRepositories

数据库有一个Customer表超过一百列(很多冗余),所以我使用DTO来填充业务层的Customer对象。在Customer类中,我也从其数据库名称中更改了许多字段的名称,例如ID为CustomerID,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基于orderBy而不是CustomerDTO期待Customer

我不希望前端知道有关CustomerDTO

的任何信息

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分: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);
    }
}

答案 1 :(得分: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);
    }

在我更改实体的那天结束时,我对更改应用程序中其他位置的代码不感兴趣。