Получить методы: один против многих

Я давно читал следующее решение о SO, но не могу найти ссылку для кредита, но здесь идет:

SELECT users.*, payments.method, payments.id AS payment_id, payments2.id
FROM users
JOIN payments
    ON users.id = payments.user_id 
LEFT JOIN payments2
    ON payments.user_id = payments2.user_id
    AND payments.id < payments2.id
WHERE payments2.id IS NULL

Чтобы понять, как это работает, просто снимите WHERE payments2.id IS NULL и вы увидите, что происходит, например, он может произвести следующий вывод (я не строю схему для проверки этого, так что это псевдовыход). Предположим, что в payments имеются следующие записи:

id | user_id | method
1  | 1       | VISA
2  | 1       | VISA
3  | 1       | VISA
4  | 1       | VISA

И вышеупомянутый SQL (без предложения WHERE payments2.id IS NULL) должен произвести:

users.id | payments.method | payments.id | payments2.id
1        | VISA            | 1           | 2
1        | VISA            | 1           | 3
1        | VISA            | 1           | 4
1        | VISA            | 2           | 3
1        | VISA            | 2           | 4
1        | VISA            | 3           | 4
1        | VISA            | 4           | NULL

Как вы можете видеть последняя строка дает желаемый результат, а поскольку нет payments2.id > 4, LEFT JOIN приводит к payments2.id = NULL.

Я нашел это решение намного быстрее (из моих ранних тестов) чем принятый ответ.

Используя другую схему, но похожий запрос, из 16095 записей:

select as1.*, as2.id
from allocation_status as1
left join allocation_status as2 
    on as1.allocation_id = as2.allocation_id
    and as1.id < as2.id
where as2.id is null;

16095 rows affected, taking 4.1ms

По сравнению с принятым ответом MAX / подзапроса:

SELECT as1.* 
FROM allocation_status as1
JOIN (
    SELECT max(id) as id
    FROM allocation_status
    group by allocation_id
) as_max on as1.id = as_max.id 

16095 rows affected, taking 14.8ms
10
задан Peter Hilton 19 September 2008 в 07:24
поделиться

22 ответа

Почему не перегружают getEmployeeName (??) метод?

getEmployeeName (международный BatchID)
getEmployeeName (возражают SSN) (плохая идея)
getEmployeeName (Строковая электронная почта)
и т.д.

Кажется пользой, к которой 'многие' приближаются мне.

9
ответ дан 3 December 2019 в 16:31
поделиться

Вы думаете C/C++.

Используйте объекты вместо байта идентификатора (или интервал).

Мое Плохое, подход перегрузки лучше и использует SSN, поскольку первичный ключ не так хорош

public ??? getEmployeeName(Object obj){

if (obj instanceof Integer){

  ...

} else if (obj instanceof String){

...

} else if .... // and so on


} else throw SomeMeaningFullRuntimeException()

return employeeName
}

Я думаю, что лучше использовать Исключения Непроверенные для передачи сигналов о неправильном входе.

Зарегистрируйте его так, клиент знает что объекты ожидать. Или создайте свои собственные обертки. Я предпочитаю первую опцию.

-2
ответ дан 3 December 2019 в 16:31
поделиться

засуньте все свои опции в перечисление, чего-то как следующее

GetEmployeeName(Enum identifier)
{
    switch (identifier)
    case eBatchID:
    {
        // Do stuff
    }
    case eSSN:
    {
    }
    case eEmailId:
    {
    }
    case eSalary:
    {
    }
    default:
    {
        // No match
        return 0;
    }
}

enum Identifier
{
    eBatchID,
    eSSN,
    eEmailID,
    eSalary
}
-1
ответ дан 3 December 2019 в 16:31
поделиться

Первое является, вероятно, лучшим в Java, полагая, что это безопасно с точки зрения типов (в отличие от другого). Кроме того, для "нормальных" типов, второе решение, кажется, только предоставляет громоздкое использование пользователю. Однако, так как Вы используете Объект в качестве типа для SSN (который имеет семантическое значение вне Объекта), Вам, вероятно, не сойдет с рук тот тип API.

В целом, в данном случае я использовал бы подход со многими методами считывания. Если все идентификаторы имеют свой собственный тип класса, я, возможно, пошел вторым путем, но переключающийся внутренне на классе вместо provided/application-defined идентификатора типа.

0
ответ дан 3 December 2019 в 16:31
поделиться

Отделение между поисковым процессом и критериями поиска jrudolf делает предложение в его примере, превосходно. Интересно, почему это не наиболее проголосовавшее решение. Я пропускаю что-то?

0
ответ дан 3 December 2019 в 16:31
поделиться

Я пошел бы с Объектами Запроса. Они работают хорошо на доступ к таблицам непосредственно. Если Вы ограничены хранимыми процедурами, они теряют часть своего питания, но можно все еще заставить его работать.

0
ответ дан 3 December 2019 в 16:31
поделиться

Я соглашаюсь с Stephan: Одна задача, одно имя метода, даже если можно сделать это несколько путей. Функция перегрузки метода была обеспечена точно для Вашего случая.

  • getEmployeeName (международный BatchID)
  • getEmployeeName (Строковая электронная почта)
  • и т.д.

И избегайте своего второго решения по всей стоимости. Это пахнет как "ваш olde пусто * C". Аналогично, передача Java "Объект" почти как плохой стиль как C "пусто *".

0
ответ дан 3 December 2019 в 16:31
поделиться

Я лично предпочитаю иметь явное именование "... ByRoomNumber", потому что, если Вы заканчиваете со многими "перегрузками", Вы в конечном счете представите нежелательные ошибки. Быть явным является, по моему скромному мнению, лучшим способом.

0
ответ дан 3 December 2019 в 16:31
поделиться

Если у Вас есть хороший дизайн, необходимо смочь определить, можно ли использовать перегружающийся подход или если Вы собираетесь столкнуться с проблемой, куда, если Вы перегружаетесь, Вы собираетесь закончить тем, что имели два метода с тем же типом параметра.

Перегрузка походит на лучший способ первоначально, но если Вы заканчиваете тем, что не были способны добавлять метод в будущем, и портить вещи с именованием это будет стычкой.

Лично я был бы для для подхода уникального имени на метод, тот способ, которым Вы не сталкиваетесь с проблемами позже с попыткой перегрузить те же методы объекта параметра. Кроме того, если бы кто-то расширил Ваш класс в будущем и реализовал другую пустоту getEmployeeName (Имя строки), то это не переопределило бы Ваш.

Подводя итоги, пойдите с названием уникального метода каждого метода, перегрузка может только вызвать проблемы в конечном счете.

0
ответ дан 3 December 2019 в 16:31
поделиться

При перезаписи вопроса, можно закончить тем, что спросили:

"ВЫБЕРИТЕ имя ИЗ..."
"ВЫБЕРИТЕ SSN ИЗ..."
"ВЫБЕРИТЕ электронную почту ИЗ..."
по сравнению с.
"ВЫБЕРИТЕ * ИЗ..."

И я предполагаю, что ответ на это легок, и все знают это.

Что происходит, если Вы изменяете класс Сотрудника? Например: необходимо удалить электронную почту и добавить новый фильтр как отдел. Со вторым решением у Вас есть огромный риск не замечать любые ошибки, если Вы просто изменяете порядок международного идентификатора "константы". С первым решением Вы будете всегда замечать, используете ли Вы метод в некоторых давно забытых классах, Вы иначе забыли бы изменять к новому идентификатору.

0
ответ дан 3 December 2019 в 16:31
поделиться

Поскольку другие предположили, что первая опция, кажется, хорошая. Второе могло бы иметь смысл при написании кода, но когда кто-то еще приезжает позже, более трудно выяснить, как использовать код. (Я знаю, у Вас есть комментарии, и можно всегда рыть глубоко в код, но GetemployeeNameById более очевиден),

Примечание: Btw, использование Перечислений могло бы быть чем-то для рассмотрения в некоторых случаях.

0
ответ дан 3 December 2019 в 16:31
поделиться

Я использовал бы первую опцию или перегрузил бы ее в этом случае, видя, поскольку у Вас есть 4 различных подписи параметра. Однако быть конкретным помогает с пониманием кода 3 месяцам с этого времени.

0
ответ дан 3 December 2019 в 16:31
поделиться

Иногда может быть более удобно использовать шаблон спецификации.

Например: GetEmployee (ISpecification <Сотрудник> спецификация)

И затем начните определять свои спецификации...

NameSpecification: ISpecification <сотрудник>
{
частное имя строки;
общедоступный NameSpecification (имя строки) {this.name = имя;}
общедоступный bool IsSatisFiedBy (Сотрудник сотрудника) {возвращает сотрудника. Имя == this.name;}
}

Спецификация NameSpecification = новый NameSpecification ("Tim");
Сотрудник tim = MyService. GetEmployee (спецификация);

1
ответ дан 3 December 2019 в 16:31
поделиться

В тривиальном случае как это я пошел бы с перегрузкой. Это:

getEmployeeName( int batchID );
getEmployeeName( Object SSN );

etc.

Только в особых случаях был бы я указывать тип аргумента в имени метода, т.е. если тип аргумента трудно определить, если существует несколько типов аргументов tha, имеет совпадающий тип данных (batchId и employeeId, оба интервала), или если методы для получения сотрудника радикально отличаются для каждого типа аргумента.

Я не вижу, почему я когда-либо использовал бы это

getEmployeeName(int typeOfIdentifier, byte[] identifier)

поскольку это требует, чтобы и вызываемый и вызывающая сторона бросили значение на основе typeOfIdentifier. Плохой дизайн.

0
ответ дан 3 December 2019 в 16:31
поделиться

Я буду использовать явные имена методов. Все, которые поддерживают тот код и меня позже, поймут то, что тот метод обходится без необходимости записать комментариям xml.

1
ответ дан 3 December 2019 в 16:31
поделиться

@Stephan: трудно перегрузить случай как это (в целом), потому что типы параметра не могли бы быть отличительными, например,

  • getEmployeeNameByBatchId (интервал batchId)
  • getEmployeeNameByRoomNumber (интервал roomNumber)

См. также эти два метода getEmployeeNameBySSN, getEmployeeNameByEmailId в исходной регистрации.

1
ответ дан 3 December 2019 в 16:31
поделиться

Первая опция, никакой вопрос. Будьте явными. Это значительно поможет в пригодности для обслуживания и нет действительно никакой оборотной стороны.

1
ответ дан 3 December 2019 в 16:31
поделиться

Методы являются идеальным примером для использования перегрузки.

getEmployeeName(int batchID)
getEmployeeName(Object SSN)
getEmployeeName(String emailID)
getEmployeeName(SalaryAccount salaryAccount)

Если методы имеют общую обработку внутри, просто запишите еще один getEmplyeeNameImpl (...) и извлеките там общий код для предотвращения дублирования

2
ответ дан 3 December 2019 в 16:31
поделиться

Мне не нравится getXByY () - который мог бы быть прохладным в PHP, но мне просто не нравится он в Java (ymmv).

Я пошел бы с перегрузкой, если у Вас нет свойств того же типа данных. В этом случае я сделал бы что-то подобное Вашей второй опции, но вместо того, чтобы использовать ints, я буду использовать Перечисление для безопасности типов и ясности. И вместо байта [], я использовал бы Объект (из-за автоупаковки, это также работает на примитивы).

3
ответ дан 3 December 2019 в 16:31
поделиться

Я пошел бы с подходом "многих". Это кажется более интуитивным мне и менее подверженным ошибке.

3
ответ дан 3 December 2019 в 16:31
поделиться

Вы могли использовать что-то как этот:

interface Employee{
    public String getName();
    int getBatchId();
}
interface Filter{
    boolean matches(Employee e);
}
public Filter byName(final String name){
    return new Filter(){
        public boolean matches(Employee e) {
            return e.getName().equals(name);
        }
    };
}
public Filter byBatchId(final int id){
    return new Filter(){
        public boolean matches(Employee e) {
            return e.getBatchId() == id;
        }
    };
}
public Employee findEmployee(Filter sel){
    List<Employee> allEmployees = null;
    for (Employee e:allEmployees)
        if (sel.matches(e))
            return e;
    return null;
}
public void usage(){
    findEmployee(byName("Gustav"));
    findEmployee(byBatchId(5));
}

Если бы Вы делаете фильтрацию по SQL-запросу, Вы использовали бы Filter интерфейс для создания оператора Where.

Хорошая вещь с этим подходом состоит в том, что можно объединить два фильтра легко с:

public Filter and(final Filter f1,final Filter f2){
    return new Filter(){
        public boolean matches(Employee e) {
            return f1.matches(e) && f2.matches(e);
        }
    };
}

и используйте его как этот:

findEmployee(and(byName("Gustav"),byBatchId(5)));

То, что Вы получаете, подобно Criteria API в в спящем режиме.

7
ответ дан 3 December 2019 в 16:31
поделиться

Является логика в каждом из тех методов в основном тем же?

Если так, отдельный метод с параметром идентификатора может иметь больше смысла (простой и уменьшающий повторный код).

Если логика/процедуры варьируется значительно между типами, метод на тип может быть предпочтен.

0
ответ дан 3 December 2019 в 16:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: