Mvc 并且只选择需要的字段
Mvc and only selecting fields needed
我似乎找不到一个可以接受的答案。
我一直看到两件大事:
1)不要在控制器中执行查询。那是业务或数据的责任。
2) 只有 select 查询中需要的列。
我的问题是这两件事有点像头,因为 UI 中显示的内容实际上决定了需要查询哪些列。这反过来导致 运行 控制器中查询的明显解决方案,您不应该这样做。我发现谷歌搜索等的任何文档似乎都可以方便地忽略这个主题并假装它不是问题。
在业务层做
现在,如果我采取另一种方式并查询业务层中的所有内容,那么我将隐式地使所有数据访问紧密反映 ui 层。查询函数的命名和 类 比我认为的任何问题都更成问题。
以一个应用程序为例,该应用程序具有多个视图,用于显示有关客户的不同信息。自然而然的做法是将这些数据传输 类 命名为与需要它们的视图相同的名称。但是,业务或服务层不知道 ui 层,因此这些数据传输中的任何一个 类 都可以在不违反任何架构规则的情况下真正重用于任何视图。那么,我如何命名所有这些变体,比如说 "Customer",其中一个 select 的名字和姓氏,另一个可能 select 姓氏和电子邮件,或者名字和城市等。你只能说出这么多 类 "CustomerSummary".
Entity Framework 和 IQueryable 很棒。但是,其他一切呢?
我知道在 entity framework 中我可以让数据层传回一个 IQuerable,它的执行被推迟,然后告诉 IQueryable 我想要什么字段。太棒了。它似乎解决了问题。对于.NET。问题是,我也做 PHP 开发。 php 的几乎所有 ORM 的设计方式都完全违背了使用 ORM 的目的。甚至那些不具备与 EF / IQueryable 相同的能力。所以我在 PHP.
中再次遇到同样的问题而没有解决方案
总结
所以,我的总体问题是如何在不完全违反 ntier 架构的所有规则的情况下只获得我需要的字段?并且没有创建不可避免地必须设计为反映 UI 层布局的数据层?
And pretty much all of the ORMs for php are designed in a way that totally defeat the purpose of using an ORM at all.
Doctrine PHP ORM 提供延迟加载到 属性 / 字段级别。您可以通过仅在需要时查询数据库的代理来完成所有工作。根据我的经验,让 ORM 一次加载整个对象在 90% 以上的情况下是更可取的。否则,如果您不小心,您最终会针对相同的记录对数据库进行多次查询。除非您的数据模型混乱并且您的行很长,否则额外的数据库喋喋不休是不值得的。
请记住,一个好的 ORM 也会提供一个内置的缓存层。一次填充整个对象并缓存它比让您的代码跟踪您需要在不同地方查询哪些字段更容易和更可扩展。
所以我的回答是,在使用 ORM 时,不要试图只查询您需要的字段。如果您只是在需要的地方手写查询,那么只查询需要的字段。但是既然你在谈论好的架构模式,我假设你没有这样做。
当然也有例外,比如查询大型数据集以进行报告或迁移。这些将需要独特的优化。
问题
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) 只有 select 您在查询中需要的列。
对于 ORM,您通常会传回整个对象。之后,您可以构建视图模型以仅包含您需要的数据。
我对您的 php 问题的建议是为您的数据设置一个网络 api。它将 return json 数据,然后您可以用您需要的任何语言进行解析。
希望对您有所帮助。
我的做法是这样的:
有一个domain object (entity, business object .. things with the same name) for Entities\Customer
, that has all fields and associated logic for all of the data, that a complete instance would have. But for persistence create two separate data mappers:
Mappers\Customer
用于处理所有数据
Mappers\CustomerSummary
仅重要部分
如果您只需要获取客户姓名和 phone 号码,您可以使用 "summary mapper",但是,当您需要检查用户的个人资料时,您可以使用 "all data mapper"。同样的分离在更新数据时也非常有用。特别是,如果您的 "full customer" 从多个表中填充。
// 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。
我似乎找不到一个可以接受的答案。
我一直看到两件大事: 1)不要在控制器中执行查询。那是业务或数据的责任。 2) 只有 select 查询中需要的列。
我的问题是这两件事有点像头,因为 UI 中显示的内容实际上决定了需要查询哪些列。这反过来导致 运行 控制器中查询的明显解决方案,您不应该这样做。我发现谷歌搜索等的任何文档似乎都可以方便地忽略这个主题并假装它不是问题。
在业务层做
现在,如果我采取另一种方式并查询业务层中的所有内容,那么我将隐式地使所有数据访问紧密反映 ui 层。查询函数的命名和 类 比我认为的任何问题都更成问题。
以一个应用程序为例,该应用程序具有多个视图,用于显示有关客户的不同信息。自然而然的做法是将这些数据传输 类 命名为与需要它们的视图相同的名称。但是,业务或服务层不知道 ui 层,因此这些数据传输中的任何一个 类 都可以在不违反任何架构规则的情况下真正重用于任何视图。那么,我如何命名所有这些变体,比如说 "Customer",其中一个 select 的名字和姓氏,另一个可能 select 姓氏和电子邮件,或者名字和城市等。你只能说出这么多 类 "CustomerSummary".
Entity Framework 和 IQueryable 很棒。但是,其他一切呢?
我知道在 entity framework 中我可以让数据层传回一个 IQuerable,它的执行被推迟,然后告诉 IQueryable 我想要什么字段。太棒了。它似乎解决了问题。对于.NET。问题是,我也做 PHP 开发。 php 的几乎所有 ORM 的设计方式都完全违背了使用 ORM 的目的。甚至那些不具备与 EF / IQueryable 相同的能力。所以我在 PHP.
中再次遇到同样的问题而没有解决方案总结
所以,我的总体问题是如何在不完全违反 ntier 架构的所有规则的情况下只获得我需要的字段?并且没有创建不可避免地必须设计为反映 UI 层布局的数据层?
And pretty much all of the ORMs for php are designed in a way that totally defeat the purpose of using an ORM at all.
Doctrine PHP ORM 提供延迟加载到 属性 / 字段级别。您可以通过仅在需要时查询数据库的代理来完成所有工作。根据我的经验,让 ORM 一次加载整个对象在 90% 以上的情况下是更可取的。否则,如果您不小心,您最终会针对相同的记录对数据库进行多次查询。除非您的数据模型混乱并且您的行很长,否则额外的数据库喋喋不休是不值得的。
请记住,一个好的 ORM 也会提供一个内置的缓存层。一次填充整个对象并缓存它比让您的代码跟踪您需要在不同地方查询哪些字段更容易和更可扩展。
所以我的回答是,在使用 ORM 时,不要试图只查询您需要的字段。如果您只是在需要的地方手写查询,那么只查询需要的字段。但是既然你在谈论好的架构模式,我假设你没有这样做。
当然也有例外,比如查询大型数据集以进行报告或迁移。这些将需要独特的优化。
问题
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) 只有 select 您在查询中需要的列。
对于 ORM,您通常会传回整个对象。之后,您可以构建视图模型以仅包含您需要的数据。
我对您的 php 问题的建议是为您的数据设置一个网络 api。它将 return json 数据,然后您可以用您需要的任何语言进行解析。
希望对您有所帮助。
我的做法是这样的:
有一个domain object (entity, business object .. things with the same name) for Entities\Customer
, that has all fields and associated logic for all of the data, that a complete instance would have. But for persistence create two separate data mappers:
Mappers\Customer
用于处理所有数据Mappers\CustomerSummary
仅重要部分
如果您只需要获取客户姓名和 phone 号码,您可以使用 "summary mapper",但是,当您需要检查用户的个人资料时,您可以使用 "all data mapper"。同样的分离在更新数据时也非常有用。特别是,如果您的 "full customer" 从多个表中填充。
// 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。