【问题标题】:Mvc and only selecting fields neededMvc 并且只选择需要的字段
【发布时间】:2016-12-26 18:48:54
【问题描述】:

我似乎找不到可以接受的答案。

我一直看到两件大事: 1)不要在控制器中执行查询。那是业务或数据的责任。 2) 只选择查询中需要的列。

我的问题是这两个东西有点像,因为 UI 中显示的内容实际上决定了需要查询哪些列。这反过来导致在控制器中运行查询的明显解决方案,这是您不应该做的。我在谷歌上搜索到的任何文档等似乎都很方便地忽略了这个主题并假装它不是问题。

在业务层做

现在,如果我采取另一种方式并查询业务层中的所有内容,那么我隐含地使所有数据访问都紧密地反映了 ui 层。查询函数和类的命名问题比我想象的要严重。

以一个应用程序为例,该应用程序具有多个视图,用于显示有关客户的不同信息。很自然的做法是将这些数据传输类命名为与需要它们的视图相同的名称。但是,业务或服务层不了解 ui 层,因此这些数据传输类中的任何一个都可以真正用于任何视图,而不会破坏任何架构规则。那么,我该如何命名所有这些变体,比如“客户”,其中一个选择名字和姓氏,另一个可能选择姓氏和电子邮件,或者名字和城市,等等。您只能将这么多类命名为“CustomerSummary”。

Entity Framework 和 IQueryable 很棒。但是,其他的呢?

我知道在实体框架中,我可以让数据层传回一个 IQueryable,其执行被推迟,然后告诉 IQueryable 我想要什么字段。这太棒了。它似乎解决了这个问题。对于.NET。问题是,我也是做PHP开发的。几乎所有 php 的 ORM 的设计方式都完全违背了使用 ORM 的目的。甚至那些不具备与 EF / IQueryable 相同的能力。所以我又回到了同样的问题,没有在 PHP 中再次解决。

总结

所以,我的总体问题是,如何在不完全违反 ntier 架构的所有规则的情况下只获得我需要的字段?并且没有创建不可避免地必须设计为反映 UI 层布局的数据层?

【问题讨论】:

  • 忽略第二条“规则”,除非您遇到真正的性能问题并且已经用尽了其他(更简单、更有效)的优化,例如缓存。

标签: php asp.net-mvc model-view-controller architecture n-tier-architecture


【解决方案1】:

我的做法如下:

Entities\Customer 提供一个domain object(实体、业务对象.. 具有相同名称的事物),它具有所有数据的所有字段和相关逻辑,即一个完整 实例将有。但是为了持久性,创建两个单独的data mappers

  • Mappers\Customer 处理所有数据
  • Mappers\CustomerSummary 仅用于重要部分

如果您只需要获取客户姓名和电话号码,您可以使用“摘要映射器”,但是,当您需要检查用户的个人资料时,您可以使用“所有数据映射器”。同样的分离在更新数据时也非常有用。特别是,如果您的“完整客户”是从多个表中填充的。

// code from a method of some service layer class
$customer = new \Model\Entities\Customer;
$customer->setId($someID);

$mapper = new \Model\Mappers\CustomerSummary($this->db);
if ($needEverything) {
    $mapper = new \Model\Mappers\Customer($this->db);
}

$mapper->fetch($customer);

至于什么去哪里,你可能想阅读this old post

【讨论】:

    【解决方案2】:

    问题

    1) 不要在控制器中执行查询。那是业务或数据的责任。

    如何设计应用程序取决于您。话虽如此,始终最好考虑最佳模式和实践。我设计控制器的方式是通过构造函数传入数据层(IRepository)并在运行时注入。

    public MyController(IRepository repo)
    

    要查询我的代码,我只需调用

    repository.Where(x=> x.Prop == "whatever")
    

    使用 IQueryable 会产生泄漏抽象问题。虽然,这可能没什么大不了的,但是您必须小心并注意如何使用您的对象,尤其是当它们包含关系数据时。查询数据层后,您将使用视图所需的适当数据在控制器操作中构建视图模型。

    public ActionResult MyAction(){
    
       var data = _repository.Single(x => x.Id == 1);
    
       var vm = new MyActionViewModel {
           Name = data.Name,
           Age = data.Age
       };
    
       return View();
    }
    

    如果我有任何复杂的查询,我会创建一个业务层来包含该逻辑。这将包括执行业务规则等。在我的业务层中,我将传入存储库并使用它。

    2) 只选择查询中需要的列。

    使用 ORM,您通常会传回整个对象。之后,您可以构建视图模型以仅包含您需要的数据。

    我对您的 php 问题的建议可能是为您的数据设置一个 web api。它会返回 json 数据,然后您可以用您需要的任何语言对其进行解析。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      几乎所有 php 的 ORM 的设计方式都完全违背了使用 ORM 的目的。

      Doctrine PHP ORM 提供了到属性/字段级别的延迟加载。您可以通过仅根据需要查询数据库的代理完成所有工作。根据我的经验,让 ORM 加载整个对象一次是最好的 90%+ 时间。否则,如果您不小心,您最终会针对相同的记录对数据库进行多次查询。除非你的数据模型很乱并且你的行很长,否则额外的 DB 喋喋不休是不值得的。

      请记住,一个好的 ORM 也会提供一个内置的缓存层。一次填充整个对象并对其进行缓存更容易且更具可扩展性,然后让您的代码跟踪您需要在不同位置查询哪些字段。

      所以我的回答是不要发疯,试图只查询你需要的字段在使用 ORM 时。如果您只是在需要的地方手工编写查询,那么只查询您需要的字段。但既然你说的是好的架构模式,我假设你没有这样做。

      当然也有例外,例如查询大型数据集以进行报告或迁移。这些将需要独特的优化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-17
        相关资源
        最近更新 更多