将信息从一个层传递到另一个层

时间:2016-09-09 07:29:51

标签: c# mvvm

抽象视图:我想将信息从一个层传递到另一个层(注意:当这个帖子有更好的标题时,请告诉我)。

我有一个ViewModel,它与我的Views和我的Service层进行通信。 我与持久层进行了服务层通信。

我们假设我有以下类:

public class EmployeeViewModel()
{
    // The following properties are binded to my View (bidirectional communication)
    public Firstname ...
    public Lastname ...
    public Email ...

    public void PerformingSearch()
    {
        ...
        EmployeeService.Search(...);
        ...
    }
}

public class EmployeeService()
{
    public List<Employee> Search(...)
    {
        // Searching in db
    }
}

将数据从ViewModel移交给我的服务层(例如执行搜索)的最佳做法是什么?

我看到一些选项(ViewModel透视图):

  1. EmployeeService.Search(名字,姓氏,电子邮件);
  2. EmployeeService.Search(employeeSearchModel); //在这种情况下,我需要另一个模型。如何实例化模型?
  3. EmployeeService.Search(本); //必须在某处完成转换
  4. 这个问题有没有设计模式?怎么称呼?什么选择最好?我错过了什么吗?

1 个答案:

答案 0 :(得分:4)

描述您的问题空间

您的特定示例告诉我,您当前的体系结构包含一个服务层,该服务层可以充当数据访问层的代理。如果没有对您的架构有更深入的了解,我会建议尽可能与您的环境允许的keep it simple解决方案。

现在让我们尝试选择策略以获得可能的解决方案模型。 您的用户故事听起来像是:“用户提交信息以获取员工列表”

您当前的用例已简化:

  1. 用户界面:提交您需要提供的一些信息;
  2. VM:接收搜索词并将其传递到服务层旁边;
  3. SL:将收到的数据发送到数据访问层(并可能将响应值更新为VM属性);
  4. DAL:在持久性存储中查找信息并返回获取的值。
  5. 重构的用例示例:

    1. VM:调用封装了所需值的查询,并设置要在UI中显示的属性。
    2. 看起来更容易吗?

      输入:Command Query Separation

      简而言之CQS:

        

      声明每个方法都应该是一个执行的命令   一个操作,或一个将数据返回给调用者的查询,但不是两者。

      在您的特定情况下,我们需要关注queries,其中:

        

      查询:返回结果,不要更改系统的可观察状态(没有副作用)。

      但这对您有何帮助?让我们看看。 CQS查询端的非常详细的解释可以在Meanwhile... on the query side of my architecture的“Steven”博客文章中完整阅读。

      应用于您的问题的查询概念

      定义查询对象的接口

      public interface IQuery<TResult> {}
      

      查询处理程序定义:

      public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
      {
          TResult Handle(TQuery query);
      }
      

      现在,这是“搜索”查询对象的实现。这实际上是“如何传递信息”问题的答案:

      public class FindEmployeeBySearchTextQuery : IQuery<Employee>
      {
          public string FirstName { get; set; }
      
          public string LastName { get; set; }
      
          public string Email { get; set; }
      }
      

      最后一个您将在查询对象中传递的查询处理程序:

      public class FindEmployeeBySearchTextQueryHandler
          : IQueryHandler<FindEmployeeBySearchTextQuery, List<Employee>>
      {
          private readonly IDbContext db;
      
          public FindEmployeeBySearchTextQueryHandler(IDbContext db)
          {
              this.db = db;
          }
      
          public List<Employee> Handle(FindEmployeeBySearchTextQuery query)
          {
              return (
                  from employee in this.db.employees
                  where employee.FirstName.Contains(query.FirstName) ||
                        employee.LastName.Contains(query.LastName) ||
                        employee.Email == query.Email
                  select employee )
                  .ToList();
          }
      }
      

      注意:此Handle()示例实现使用实体框架“IDbContext,您必须根据需要对其进行返工/修改(ADO.NET,NHibernate等)。

      最后在你的视图模型中:

      public class EmployeeViewModel()
      {
          private readonly IQueryHandler _queryHandler;
          public EmployeeViewModel(IQueryHandler queryHandler) 
          {
              _queryHandler = queryHandler;
          }
      
          public void PerformingSearch()
          {
              var query = new FindEmployeeBySearchTextQuery
              {
                  FirstName = "John", 
                  LastName = "Doe",
                  Email = "stack@has.been.over.flowed.com"
              };
      
              List<Employee> employees = _queryHandler.Handle(query);
      
              // .. Do further processing of the obtained data
          }
      }
      

      此示例假定您正在使用依赖注入 您将IQueryHandler实现注入到视图模型构造函数中,然后使用接收到的实现。

      使用这种方法,您的代码变得更清晰,更多的用例驱动,并且可以更好地隔离责任,您可以通过进一步的跨领域问题轻松测试和装饰。