Mvc并且只选择所需的字段

时间:2016-08-19 14:45:10

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

我似乎无法找到一个可以接受的答案。

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

我的问题是,由于UI中显示的内容实际上决定了哪些列需要查询,因此这两件事情都很糟糕。这反过来导致在控制器中运行查询的明显解决方案,您不应该这样做。我发现谷歌搜索的任何文档似乎都很方便地忽略了这个主题,并假装它不是问题。

在业务层

中执行此操作

现在,如果我采用另一种方式并查询业务层中的所有内容,那么我隐含地使所有数据访问密切反映ui层。对于查询函数和类的命名而言,这比我想象的更多。

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

实体框架和IQueryable很棒。但是,其他一切呢?

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

将其包装

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

3 个答案:

答案 0 :(得分:1)

  

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

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

请记住,好的ORM还会提供内置的缓存层。填充整个对象并缓存它更容易,更易于扩展,然后让代码跟踪您需要在不同位置查询的字段。

所以我的答案是,在使用ORM 时,不要试图只查询所需的字段。如果您只是在需要的地方手动编写查询,那么只查询您需要的字段。但是既然你在谈论好的建筑模式,我认为你并没有这样做。

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

答案 1 :(得分:1)

<强>问题

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数据,然后您可以使用您需要的任何语言进行解析。

希望这有帮助。

答案 2 :(得分:0)

我这样做的方式如下:

Entities\Customer设置一个domain object(实体,业务对象......具有相同名称的东西),其中包含所有数据的所有字段和关联逻辑,完成< / strong>实例会有。但是对于持久性创建两个单独的data mappers

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

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

// 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