【问题标题】:BestPractice: How to display a many-to-many association in a view in a clean way?最佳实践:如何在视图中以干净的方式显示多对多关联?
【发布时间】:2010-02-24 12:27:46
【问题描述】:

我正在使用 NHibernate,并且员工和团队之间存在多对多关联。

现在我想显示所有员工及其团队成员的姓名。

可能性一:

  • 使用 AutoMapper 并创建一个包含 Employee 属性和团队名称的 DTO(渴望加载团队)
  • 在视图中显示 DTO

可能性2:

  • 创建一个名为 EmployeeTeam 的新实体并将其与 NHibernate/FluentNHibernate 映射(该实体充当数据库中 Employee 和 Team 之间的关系表)
  • 使用即时加载加载 TeamEmployee,包括 Employee 和 Team
  • 显示 EmployeeTeam 实体
  • 使用 EmployeeTeam 成员(EmployeeTeam.Employee.Name、EmployeeTeam.Team.Name)

可能性3:

  • 作为可能性 1 和 2
  • 为 EmployeeTeam 使用 DTO

可能性4:

  • 使用 ICriteria API
  • 使用 AliasToBeanResultTransformer(没用这个)

可能性5:

  • 使用 LINQ 到 NHibernate
  • 我认为我仍然需要 EmployeeTeam 实体(目前不在我的领域模型中)

解决这个问题的最佳做法是什么?

还有其他建议吗?

【问题讨论】:

  • 这里您需要注意的一件事是 SELECT N+1 问题。也就是说,对于每个员工,您不会对他们的所有团队进行另一个查询。对于任何 ORM 策略,Eager fetching 都应该处理好它。

标签: c# nhibernate automapper dto


【解决方案1】:

这听起来像是一场 UI 噩梦,但您可以将员工列表传递给视图。然后有一个嵌套循环,在循环通过员工的循环中循环通过团队。在 Asp.Net MVC 中看起来像这样 -

<table>
    <thead>
        <tr>
            <td>Employee</td>
            <td>Team</td>
        </tr>
    </thead>
    <% foreach(var employee in Model.Employees) { %>
        <% foreach (var team in employee.Teams) { %>
            <tr>
                <td><%=employee.Name %></td>
                <td><%=team.Name %></td>
            </tr>
        <% } %>
    <% } %>
</table>

您将在以下情况下使用 ViewModel (DTO) -

  • 如果域模型非常复杂且简化有助于提高可读性
  • 如果您需要在显示前对视图数据进行一些修改
  • 如果您需要在回发时更新值。

我会避免选项二,因为它只会给您的域增加不必要的复杂性(从我可以从提供的当前信息中推断出的):-)

更新

如果您希望仍然显示没有团队的员工,您可以在视图中进行设置...

<table>
    <thead>
        <tr>
            <td>Employee</td>
            <td>Team</td>
        </tr>
    </thead>
    <% foreach(var employee in Model.Employees) { %>
        <tr>
            <% if (employee.Teams.Any()) { %>
                <td><%=employee.Name %></td>
                <td> - </td>
            <% } else { %>
                <% foreach (var team in employee.Teams) { %>
                    <td><%=employee.Name %></td>
                    <td><%=team.Name %></td>
                <% } %>
            <% } %>
        </tr>
    <% } %>
</table>

显然,像这样的 UI 调整越多,您就越有可能希望使用 ViewModel 来清理您的 View。如果您发现由于内联代码引用的数量而导致您的视图开始变得不可读,那么这通常表明 ViewModel (DTO) 将适用:-)

【讨论】:

  • 您的视图看起来像我的第一个方法。问题在于,当员工没有团队时,第二个 foreach 循环不会执行,因此不会显示员工。
  • 我在我的答案中添加了一个更新,这应该有助于解决没有团队的员工的问题。
  • 您可能还想用 if 语句包装整个表,该语句查询是否有任何员工属于团队... Model.Employees.Where(e => e.Teams. Any()).Any()
  • 我读到视图中的逻辑很糟糕:o 因为关注点分离......我也有这个想法,但它不是干净的方式 =)
  • 视图中的业务逻辑不好。这不是业务逻辑,这是显示代码。您正在获取一个包含要显示的数据的对象,并以某种方式显示该数据。所以问题不在于视图中的“逻辑”,而在于视图的可读性。它可能会进入视图中代码中过多的显示操作会使视图混乱的阶段。在这种情况下,ViewModel 会简化事情。当您的团队中有一个前端开发人员将修改不完全理解 C# 的视图时,尤其如此
【解决方案2】:

这取决于您是否要严格使用 DTO 将业务逻辑与表示逻辑(架构决策)分开。在这种情况下,我更喜欢解决方案 1。

如果您对像 EmployeeTeam 这样的实体有行为,或者会有重用(例如在报告中),那么我更喜欢解决方案 2。

【讨论】:

  • EmployeeTeam 在域模型中不存在。
【解决方案3】:

使用要显示为属性的字段创建视图 dto。 使用 automapper - 将实体属性映射到您的新 dto:

Mapper.CreateMap<Obj1, NewObjDto>()
                .ForMember(dest => dest.Prop1, opt => opt.MapFrom(src => src.Obj1.Prop1));

换句话说 - 您的视图 dto 不必类似于您的域对象。

w://

【讨论】:

  • 这是我现在使用的方法,但我问自己是否真的有必要。
猜你喜欢
  • 1970-01-01
  • 2012-01-16
  • 2011-12-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
相关资源
最近更新 更多