3

我正在开发一个项目,该项目使用汇编器模式将 LinqToEntity 实体组装成服务级别的数据传输对象,然后将其传递给客户端层以供使用。该方法已将实体对象转换为提供特定于服务调用的信息的简化的平面对象。

例如。

// Original Entity looks something like this
public class PersonEntity
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int MotherId { get; set; }  
   public PersonEntity Mother { get; set; }
   // lots of other properties
}

// Flattened DTO
public class PersonSummaryInfo
{
  public int Id { get; set; }
  public string FullName { get; set; }
  public string MothersFullName { get; set; }
}

在此示例中,汇编器将创建 PersonSummaryInfo,构建流程的 FullNames 部分。

我现在面临一些第 3 方控件(Telerik ASP.NET MVC GridControl)的问题,其中控件设置为根据其模型的属性进行过滤(使用 IQueryable)。似乎您有一个单层设计并将您的数据库实体直接泵入视图,我无法忍受。

试图将其合并到我的逻辑中,GridControl 绑定到我的 DTO 而不是实体,这一切都很好,直到它尝试对任何东西进行排序。我以非常通用的方式将所有 IQueryable 的东西都推到了我的服务中,以使其对此负责。排序尝试排序,比如 DTO 上的 MothersFullName(它的行为是将“MothersFullName”作为字符串传递给您的排序逻辑),这被推送到我的服务,该服务通过反射尝试对实体进行排序,利用 IQueryable 惰性加载,但当然在执行查询时,会抛出异常,因为“MothersFullName”不是原始实体的属性。

是否有一个很好的策略来处理这种实现?一旦 DTO 回到应用程序的服务层,将其有效地“分解”回其 ORM 实体是一种好习惯吗?还是传递更丰富的对象更好,这些对象对它们有更多的了解(例如如何使用 FirstName 和 LastName 对全名进行排序)?

我的要求的关键是:

  • 使用花哨的 Telerik 控件,因为他们喜欢它
  • 服务级别的延迟加载结果(即不带回 200 万条记录,只显示 10 条)
  • 支持过滤、分页等
  • 完善的架构实现
4

3 回答 3

4

你有几个选择。首先,确实能够绑定到 IQueryable,因为当然就开发时间而言,这是最快(也是最常见)的方式。

在您的情况下(ORM 之上的完整服务层)情况有点不同。我个人建议您深入挖掘并为您的网格提供自定义绑定。您将获得一个 GridCommand 对象,您可以查询该对象以进行排序和过滤,并使用该对象向您的服务层询问数据。这是一个很好的地方来提及解决您面临的问题的简单方法(这是您的表达式基于 DTO 属性)。您可以尝试使用Dynamic Linq。只需从表达式构造您的字符串查询并将它们传递给您的 DAL。

事实上,这是 Telerik 的另一个产品 OpenAccess ORM 建议的最佳实践。OpenAccess SDK包含几个示例(尤其是 WCF 普通服务),它们使用与您的架构相似的架构。该产品还提供了一个代码生成工具,可提供整个服务层。

于 2012-06-09T17:42:45.980 回答
0

您是否仅将 RadGrid 用于其开箱即用的排序功能?我遇到了同样的问题,最后只使用了 RadListView 并将寻呼机/排序插入其中。使用模板,您可以通过 SortExpession 属性准确地告诉它要排序的内容。然后它只是关于触发正确的事件。这是我的事件处理程序,你可以设置任何你能拿到的东西来触发它。我不确定这是否是一个解决方案,但希望它可以帮助您找到一个:

protected void SortSearchTickets(object sender, RadComboBoxSelectedIndexChangedEventArgs e)
    {
        var selectedValue = e.Value;
        lsvSearchResults.SortExpressions.Clear();
        var sortExp = new RadListViewSortExpression();

        switch (selectedValue)
        {
            case "ID":
                sortExp.FieldName = "TicketID";
                break;
            case "TicketType":
                sortExp.FieldName = "TypeDescription";
                break;
            case "Subject":
                sortExp.FieldName = "Subject";
                break;
            case "Status":
                sortExp.FieldName = "Status.Key";
                break;
            case "DueDateDesc":
                sortExp.FieldName = "DueDate";
                sortExp.SortOrder = RadListViewSortOrder.Descending;
                break;
            case "DueDateAsc":
                sortExp.FieldName = "DueDate";
                sortExp.SortOrder = RadListViewSortOrder.Ascending;
                break;
            case "Assigned To":
                sortExp.FieldName = "AssignedTo.Key";
                break;
            case "Assigned By":
                sortExp.FieldName = "AssignedBy.Key";
                break;
            default:
                break;
        }
        lsvSearchResults.SortExpressions.AddSortExpression(sortExp);
        lsvSearchResults.Rebind();
    }
于 2012-06-08T20:36:48.187 回答
0

用这个解决方案。

创建包含 Grid 特定列的 sql 视图。然后使数据传输对象使用与视图完全匹配的属性。这不是实现这一目标的最干净或最强大的方法,但至少它可以从我不需要的项目中获取我的数据引用。

没有使用动态 linq,而是保留了我的通用方法并使用反射来获取列名以进行匹配。没有因为我们已经实现了整个服务层而选择 Telerik 的 Open Access,但这听起来是一个不错的解决方案。

它仍然是 IQueryable,因此它非常有效地运行良好(仅依赖于开发人员来确保 GridViews 与 GridViewModels 匹配,属性的属性)。

于 2012-07-13T16:07:07.343 回答