Вам не хватает u.username
в group by
, также COUNT(a.id)
должно измениться на COUNT(distinct a.id)
:
SELECT u.id, u.username, COUNT(distinct a.id) AS total_articles, COUNT(c.id) AS total_comments FROM users u
LEFT JOIN articles a ON u.id = a.user_id
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY u.id, u.username;
Однако, я думаю, что, что вам на самом деле нужно что-то другое, чем предложенный вами запрос. Вы сказали, что вам нужно общее количество статей для каждого пользователя и общее количество комментариев для каждой статьи . Это означает, что вам нужно два отдельных запроса:
SELECT a.id article_id , COUNT(c.id) AS total_comments
FROM articles a
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY a.id
SELECT u.id, u.username, COUNT(distinct a.id) AS total_articles
FROM users u
LEFT JOIN articles a ON u.id = a.user_id
GROUP BY u.id, u.username;
Глобальные данные не являются настолько же неправильными, как требуют многие пуристы OO!
, В конце концов, при реализации классов OO у Вас есть обычно использование API к Вашей ОС. Какого черта это, если это не огромная груда глобальных данных и сервисов!
при использовании некоторого глобального материала в программе Вы просто расширяете эту огромную среду, которую Ваша реализация класса может уже видеть ОС с небольшим количеством данных, которые являются зависящими от домена к Вашему приложению.
Передающие указатели/ссылки везде часто преподаются в курсах OO и книгах, академически это звучит хорошим. Практично, это часто нужно, но это дезинформировано для следования этому правилу вслепую и абсолютно. Для достойной размерной программы можно закончить с грудой ссылок, передаваемых повсеместно, и она может привести к абсолютно ненужной работе тяжелой работы.
Глобально доступные сервисы/поставщики данных (абстрагированный далеко позади хорошего интерфейса, очевидно) являются в значительной степени необходимостью в достойном размерном приложении.
Вы могли бы хотеть думать об изменении требования, чтобы много объектов знало о тех же структурах данных. Одна причина там, кажется, не чистое OO, которым способ обменяться данными состоит в том, что обмен данными не очень объектно-ориентирован.
необходимо будет посмотреть на специфические особенности приложения, но общее представление состоит в том, чтобы иметь один объект, ответственный за совместно используемые данные, который предоставляет услуги другим объектам на основе данных, инкапсулировавших в нем. Однако эти сервисы должны не , включают предоставление других объектов структур данных - просто предоставление других объектов сведений, которые они должны встретить их обязанности и работающие мутации на структурах данных внутренне.
Я должен действительно действительно отговорить Вас использовать опцию 3 - создание статичных данных. Я работал над несколькими проектами, где ранние разработчики сделали некоторые базовые данные статичными, только чтобы позже понять, что они действительно должны были выполнить две копии программы - и подверглись огромному объему работы, делающему нестатичные данные и тщательно включающему ссылки во все.
Так, по моему опыту, если Вы делаете 3), Вы в конечном счете закончите тем, что делали 1) в два раза стоимость.
Идут для 1, и быть мелкомодульным, о каких структурах данных Вы ссылаетесь от каждого объекта. Не используйте "объекты контекста", просто передавайте в точно необходимых данных. Да, это делает код более сложным, но зато, это делает это более ясным - то, которое FwurzleDigestionListener
содержит ссылку и на Fwurzle
и на DigestionTract
, сразу дает читателю общее представление о его цели.
И по определению, если формат данных изменения, так будет классы, которые воздействуют на него, таким образом, необходимо изменить их так или иначе.
Мне не нравится ни одно из Ваших предлагаемых решений:
Я склонен использовать 3) и быть очень осторожным относительно синхронизации и блокирующий через потоки. Я соглашаюсь, что это - меньше OO, но тогда Вы признаетесь в наличии глобальных данных, которые являются очень неOO во-первых.
не становятся слишком одержимыми тем, придерживаетесь ли Вы просто одной методологии программирования или другого, найдите решение, которое соответствует Вашей проблеме. Я думаю, что существуют совершенно допустимые контексты для одиночных элементов (Регистрирующийся, например).
Я предпочитаю использовать шаблон "одиночка", как описано в книге GoF для этих ситуаций. Одиночный элемент не является тем же как ни одной из этих трех опций, описанных в вопросе. Конструктор является частным (или защищенный) так, чтобы это не могло использоваться просто нигде. Вы используете получение () функция (или независимо от того, что Вы предпочитаете называть ее) получить экземпляр. Однако архитектура singleton-класса гарантирует, что каждый вызов для получения () возвращает тот же экземпляр.
Опция 3), в то время как не пуристское OO, имеет тенденцию быть самым разумным решением. Но я не сделал бы Ваш класс одиночным элементом; и используйте некоторый другой объект в качестве статического 'словаря' для управления теми совместно используемыми ресурсами.
Мы должны заботиться, чтобы не перепутать Объектно-ориентированное проектирование с Объектно-ориентированной Реализацией. Al слишком часто, термин, Дизайн OO используется для оценки реализации, так же, как, по моему скромному мнению, это здесь.
Если в Вашем дизайне Вы видите много объектов, имеющих ссылку на точно тот же объект, который означает много стрелок. Разработчик должен чувствовать зуд здесь. Он должен проверить, является ли этот объект просто наиболее часто используемым, или если это - действительно утилита (например, фабрика COM, реестр некоторого вида...).
От требований проекта он видит, должен ли это действительно быть одиночный элемент (например, 'Интернет'), или если объект совместно используется, потому что это слишком общее или слишком дорогим или безотносительно.
Когда Вас просят реализовать Дизайн OO на языке OO, Вы сталкиваетесь с большим количеством решений, как то, которое Вы упомянули: как я должен реализовать все стрелки к часто используемому объекту в дизайне?
В этом суть, где вопросы рассмотрены о 'статическом участнике', 'глобальной переменной', 'класс бога' и 'a-lot-of-function-arguments''.
Стадия проектирования должна была разъясниться, должен ли объект быть одиночным элементом или нет. Фаза реализации выберет, как эта единственность будет представлена в программе.
Я использую комбинацию наличия одного глобального объекта и передачи интерфейсов на пути конструкторы.
От одного основного глобального объекта (обычно называемый в честь того, чем Вашу программу называют или делает), можно запустить другой globals (возможно, которые имеют их собственные потоки). Это позволяет Вам управлять установкой объектов программы в конструкторе основных объектов и разъединении их снова в правильном порядке, когда приложение останавливается в этом деструкторе основных объектов. Используя статические классы непосредственно делает это хитрым для инициализирования/деинициализирования любых ресурсов эти классы использование управляемым способом. Этот основной глобальный объект также имеет свойства для того, чтобы достигнуть интерфейсы различных подсистем Вашего приложения, которым различные объекты могут хотеть овладеть, чтобы сделать их работу.
я также передаю ссылки на соответствующие структуры данных в конструкторов некоторых объектов, где я чувствую, что полезно изолировать те объекты от остальной части мира в рамках программы, когда они только должны быть обеспокоены небольшой частью его.
, Захватывает ли объект глобальный объект и перемещается по его свойствам для получения интерфейсов, которые он хочет или передается интерфейсы, которые он использует через его конструктора, вопрос вкуса и интуиции. Любой объект Вы реализуете это, Вы думаете, мог бы быть снова использован в некотором другом проекте, должны определенно быть переданные структуры данных, которые он должен использовать через его конструктора. Объекты, которые захватывают глобальный объект, должны больше относиться к инфраструктуре Вашего приложения.
Объекты, которые получают интерфейсы, которые они используют через конструктора, вероятно, легче к модульному тесту, потому что можно подать их ложный интерфейс, и щекотать их методы, чтобы удостовериться, что они возвращают правильные аргументы или взаимодействуют с ложными интерфейсами правильно. Для тестирования объектов, которые получают доступ к основному глобальному объекту необходимо копировать основной глобальный объект так, чтобы, когда они запрашивают интерфейсы (я часто называю эти сервисы) от него они получили соответствующие фиктивные объекты и могли быть протестированы против них.