Как известно, есть два способа сформировать интерфейс изменения объекта в DAO:
a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый.
b) save, который умеет и создавать, и обновлять объекты
Здравствуйте, scf, Вы писали: scf>Вы за какой вариант и почему?
Я за DDD. У каждого варианта своя семантика, которая может быть предпочтительна для разных предметных областей и сценариев.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
Здравствуйте, Sharov, Вы писали:
S>Здравствуйте, scf, Вы писали:
scf>>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>>b) save, который умеет и создавать, и обновлять объекты
S>За а). На REST хорошо отображается.
А если Save > PUT (но тут смотря как соответствие определяется)
Здравствуйте, Doc, Вы писали:
Doc>Здравствуйте, Sharov, Вы писали:
S>>Как понять Save > PUT? Типа Save больше (может выполнить) чем Put? Doc>Save отобразить на Put
Ну тогда save ломает srp -- и создание и обновление объектов, все на нем.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
за а). обычно известно что делается в коде — добавляеш или обновляеш объект.
и если вдруг какая ошибка и пытаешся обновить объект, а его нет (нетот идентифкатор получен, или уже удалён)
то получиш вменяемую ошибку (объект не существует), в случае б) проблема вылезет сильно позже с большим кол-вом времени
потраченным на поиск и возможно и ещё рядом неприятных побочных проявлений.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
Вариант а), если используется паттерн типа ActiveRecord. Вариант b) — если UnitOfWork.
Если по задаче будет нужно, то в варианте а) так же появится метод save, только где-то в другом месте или просто рядом с create/update, не вижу смысла им ограничивать интерфейс DAO.
Здравствуйте, Sharov, Вы писали:
S>Ну тогда save ломает srp -- и создание и обновление объектов, все на нем.
Ну почему же. Зависит от того, что называть responsibility в данном случае. Если "создавать объект в базе" и "обновлять существующий", то да, ломает. А если иметь в виду "сохранить в базу", то там уже фиолетово, произошёл INSERT или UPDATE на уровне SQL. Главная responsibility — данный объект сохранён в базу — выполнена.
Здравствуйте, scf, Вы писали:
scf>Вы за какой вариант и почему?
Если смотреть на реальные бизнес сценарии, то могу припомнить только 2:
— работает сервсис которому падать нельзя. Ему нужно перезаписать объект и его не волнует что было до этого. Если АПИ предлагает только стандартные CRUD методы, то выходит такое:
var newObj = new {};
try{
var obj = api.Read();
api.Update(newObj);
}
catch(NotFoundException)
{
api.Create(newObj);
}
— есть ГУИ и пользователь хочет создать/поменять объект. Но если кто-то еще уже сделал изменения когда он несколько минут вводил свои изменения и нажал потом "Сейв" — то показать алерт и спросить — перезаписать или отклонить свои изменения.
Для того чтобы удовлетворить все потребности мы у себя исполуем такое:
class API
{
//Create or update
ObjectVersion Save(object obj);
//when expectedVersion = 0 - Create if and only if obj is not exist
//when expectedVersion > 0 - Update with concurrency check
ObjectVersion Save(object obj, int expectedVersion);
}
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты scf>Вы за какой вариант и почему?
Во втором случае проблемы с идемпотентностью, поэтому в лес.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
Я за тот вариант, с которым будет легче писать клиентский код.
В rest будет одна операция put, которая create и update в одном. Поэтому в rest удобнее save.
В типовом UI-сценарии на уровне вызывающего кода известно создается объект или нет (create или update). Если клиентский код будет выглядеть как create(obj) и update(obj) без дополнительных условий, то можно заменить на save(obj)
Поэтому в целом save универсальнее, но могут быть исключения и вообще говоря зависит от того, что внутри save.
Здравствуйте, scf, Вы писали:
scf>Как известно, есть два способа сформировать интерфейс изменения объекта в DAO: scf>a) create/update, где первое возвращает ошибку при попытке сохранить существующий объект, а второе — при попытке обновить новый. scf>b) save, который умеет и создавать, и обновлять объекты
scf>Вы за какой вариант и почему?
За оба. В большинстве случаев приложение прекрасно знает, сохраняет оно новый объект или обновляет существующий. Никакого смысла использовать универсальный метод нет. Кроме того это может помочь отловить баг. При всём этом в базе данных сохранение и обновление отличаются, поэтому это должны быть две разные операции. Но могут быть случаи, когда полезен третий вариант и он тоже должен быть.