Я не могу найти приемлемый ответ на это.
Я продолжаю видеть две большие вещи:
1) Не выполняйте запросы в контроллере. Это ответственность бизнеса или данных.
2) Выберите только те столбцы, которые вам нужны в запросе.
Моя проблема заключается в том, что эти две вещи вроде торцевых головок, поскольку то, что отображается в пользовательском интерфейсе, действительно определяет столбцы, которые необходимо запрашивать. Это, в свою очередь, приводит к очевидному решению выполнения запроса в контроллере, что вы не должны делать. Кажется, что любая документация, которую я нашел в Google, удобно игнорирует эту тему и делает вид, что это не проблема.
Теперь, если я возьму это другим способом и сделаю запрос ко всему на бизнес-уровне, то я неявным образом заставляю весь доступ к данным точно отражать уровень пользовательского интерфейса. Это больше проблема с именованием функций и классов запросов, чем все, что я думаю.
Возьмем, к примеру, приложение с несколькими представлениями для отображения различной информации о клиенте. Естественно сделать так, чтобы эти классы передачи данных назывались так же, как и представления, которым они нужны. Но бизнес или сервисный уровень не знает уровня пользовательского интерфейса, и поэтому любой из этих классов передачи данных может быть действительно повторно использован для ЛЮБОГО представления без нарушения каких-либо архитектурных правил. Итак, как я называю все эти варианты, скажем, «Клиент», где один выбирает имя и фамилию, другой может выбрать фамилию и адрес электронной почты, или имя и город, и так далее. Вы можете только назвать так много классов «CustomerSummary».
Я понимаю, что в структуре сущностей у меня может быть уровень данных, передающий обратно IQuerable, выполнение которого отложено, а затем просто сообщаю этому IQueryable, какие поля я хочу. Это прекрасно. Кажется, чтобы решить проблему. Для .NET. Проблема в том, что я также занимаюсь разработкой PHP. И почти все ORM для php разработаны таким образом, чтобы полностью отказаться от цели использования ORM. И даже те, кто не обладает такой же способностью, как EF / IQueryable. Так что я вернулся к той же проблеме без решения снова в PHP.
Итак, мой общий вопрос: как мне получить только те поля, которые мне нужны, без лишних усилий по всем правилам более старой архитектуры? И без создания слоя данных, который неизбежно должен быть разработан, чтобы отразить макет уровня пользовательского интерфейса?
И почти все ORM для php разработаны таким образом, чтобы полностью отказаться от цели использования ORM.
Doct PHP 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) Выберите только те столбцы, которые вам нужны в запросе.
С ORM вы обычно возвращаете весь объект обратно. После этого вы можете построить модель представления, включающую только те данные, которые вам нужны.
Мое предложение для вашей проблемы php, возможно, настроить веб-API для ваших данных. Он вернет данные json, которые вы сможете затем проанализировать на любом языке, который вам нужен.
Надеюсь это поможет.
Я делаю это следующим образом:
Есть доменный объект (сущность, бизнес-объект .. вещи с одинаковым именем) для Entities\Customer
, который имеет все поля и связанную логику для всех данных, что полный экземпляр будет иметь. Но для настойчивости создать два отдельных картографы данных:
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);
Что касается того, что идет куда, вы, возможно, захотите прочитать этот старый пост.