Как слой сервиса вписывается в мою реализацию репозитория?
Я создал класс модели POCO и класс репозитория, который обрабатывает персистентность. Поскольку POCO не может получить доступ к репозиторию, в репозитории есть много задач бизнес-логики, которые не кажутся правильными. Из того, что я прочитал, похоже, мне нужен слой сервиса, который находится между потребителями пользовательского интерфейса и слоем репозитория. То, что я не уверен в том, как именно это должно работать...
в дополнение к уровню сервиса, должен ли также быть отдельный уровень бизнес-логики, или это роль уровня сервиса?
должна ли быть одна служба в репозитории?
является ли уровень сервиса единственным способом, которым пользовательский интерфейс может копировать объекты модели, или репозиторий предоставляет новый экземпляр модели для службы?
помещаю ли я свой параметр, модель и другие проверки в уровень сервиса, которые делают такие вещи, как проверка, чтобы убедиться, что вход действителен и что элемент для обновления существует в базе данных раньше обновление?
может ли модель, репозиторий и пользовательский интерфейс выполнять вызовы на уровень сервиса, или это только для пользовательского интерфейса?
предполагается ли, что уровень сервиса-это все статические методы?
каков был бы типичный способ вызова уровня сервиса из пользовательского интерфейса?
какие проверки должны быть на модели против уровня сервиса?
вот пример кода для моих существующих слоев:
public class GiftCertificateModel
{
public int GiftCerticiateId {get;set;}
public string Code {get;set;}
public decimal Amount {get;set;}
public DateTime ExpirationDate {get;set;}
public bool IsValidCode(){}
}
public class GiftCertificateRepository
{
//only way to access database
public GiftCertificateModel GetById(int GiftCertificateId) { }
public List<GiftCertificateModel> GetMany() { }
public void Save(GiftCertificateModel gc) { }
public string GetNewUniqueCode() { //code has to be checked in db }
public GiftCertificateModel CreateNew()
{
GiftCertificateModel gc = new GiftCertificateModel();
gc.Code = GetNewUniqueCode();
return gc;
}
}
обновление:
Я в настоящее время с помощью веб-формы и классический ADO.NET. Я надеюсь, чтобы перейти к MVC и в ef4, в конце концов.
обновление: большое спасибо @Лестер за его большое объяснение. Теперь я понимаю, что мне нужно добавить уровень сервиса для каждого из моих репозиториев. Этот уровень будет единственным способом взаимодействия пользовательского интерфейса или других служб с репозиторием и будет содержать любые проверки, которые не соответствуют объекту домена (например, проверки, которые необходимо вызвать РЕПО)
public class GiftCertificateService()
{
public void Redeem(string code, decimal amount)
{
GiftCertificate gc = new GiftCertificate();
if (!gc.IsValidCode(code))
{
throw new ArgumentException("Invalid code");
}
if (amount <= 0 || GetRemainingBalance(code) < amount)
{
throw new ArgumentException("Invalid amount");
}
GiftCertificateRepository gcRepo = new GiftCertificateRepository();
gcRepo.Redeem(code, amount);
}
public decimal GetRemainingBalance(string code)
{
GiftCertificate gc = new GiftCertificate();
if (!gc.IsValidCode(code))
{
throw new ArgumentException("Invalid code");
}
GiftCertificateRepository gcRepo = new GiftCertificateRepository();
gcRepo.GetRemainingBalance(code);
}
public SaveNewGC(GiftCertificate gc)
{
//validates the gc and calls the repo save method
//updates the objects new db ID
}
}
вопросы
добавляю ли я к сервису те же (и, возможно, больше) свойства, что и в моей модели (количество, код и т. д.), Или я предлагаю только методы, которые принимают объекты GiftCertificate и прямые параметры?
создаю ли я экземпляр по умолчанию сущности GiftCertificate при вызове конструктора службы или просто создаю новые по мере необходимости (например, для методов проверки в служба, которая должна вызывать методы проверки в сущности? Кроме того, тот же вопрос о создании экземпляра репозитория по умолчанию...?
Я знаю, что я предоставляю функциональность РЕПО через сервис, я также предоставляю методы из сущности (например, IsValidCode и т. д.)?
это нормально для пользовательского интерфейса, чтобы просто создать новый объект GiftCertificate непосредственно без прохождения службы (например-для вызова методов проверки параметров из сущность.) Если нет,то как его обеспечить?
на уровне пользовательского интерфейса, когда я хочу создать новый подарочный сертификат, я вызываю проверки модели/службы (например, IsValidExpirationDate и т. д.) непосредственно из уровня пользовательского интерфейса или сначала гидратирую объект, а затем передаю его для проверки, а затем возвращаю какую-то сводку проверки обратно в пользовательский интерфейс?
кроме того, если я хочу выкупить из слоя пользовательского интерфейса, я сначала вызываю проверку модели / службы методы из пользовательского интерфейса, чтобы дать обратную связь с пользователем, а затем вызвать метод Redeem, который будет снова запускать те же проверки внутри?
пример вызова службы для выполнения операции выкупа из пользовательского интерфейса:
string redeemCode = RedeemCodeTextBox.Text;
GiftCertificateService gcService = new GiftCertificateService();
GiftCertificate gc = new GiftCertificate(); //do this to call validation methods (should be through service somehow?)
if (!gc.IsValid(redeemCode))
{
//give error back to user
}
if (gcService.GetRemainingBalance(redeemCode) < amount)
{
//give error back to user
}
//if no errors
gcService.Redeem(code,amount);
пример создания нового подарочного сертификата от UI:
GiftCertificateService gcService = new GiftCertificateService();
GiftCertificate gc = new GiftCertificate();
if (!gc.IsValidExpDate(inputExpDate))
{
//give error to user..
}
//if no errors...
gc.Code = gcService.GetNewCode();
gc.Amount = 10M;
gc.ExpirationDate = inputExpDate;
gcService.SaveNewGC(gc);
//method updates the gc with the new id...
что-то кажется неправильным в том, как создаются GCs и как проверки разделяются между сущностью/сервисом. Пользователь/потребитель не должен будьте обеспокоены тем, какие проверки находятся в каком месте... совет?
3 ответов:
посмотри S#ARP Architeture . Это как лучшие практики архитектурной основы для строительства ASP.NET приложения MVC. Общий шаблон архитектуры должен иметь 1 репозиторий на объект, который отвечает только за доступ к данным и 1 службу на репозиторий, который отвечает только за бизнес-логику и связь между контроллерами и службами.
чтобы ответить на ваши вопросы, основанные на S#ARP Architeture:
в дополнение к уровень сервиса, должен ли также быть отдельный уровень бизнес-логики, или это роль уровня сервиса?
модели должны отвечать за проверку на уровне полей (например. использование обязательных атрибутов полей), в то время как контроллеры могут проверять данные перед сохранением (например. проверка состояния перед сохранением).
должен ли быть один уровень обслуживания в репозитории?
да - должен быть один сервис на репозиторий (не 1 уровень сервиса для каждого репозитория, но я предполагаю, что вы имели в виду это).
является ли уровень сервиса единственным способом, которым пользовательский интерфейс может копировать объекты модели, или репозиторий предоставляет новый экземпляр модели для службы?
репозитории и службы могут возвращать один объект, коллекцию объектов или объекты передачи данных (DTOs) по мере необходимости. Контроллеры передадут эти значения в статический метод конструктора в модели, который вернет экземпляр модель.
ex с помощью DTOs:
GiftCertificateModel.CreateGiftCertificate(int GiftCerticiateId, string Code, decimal Amount, DateTime ExpirationDate)помещаю ли я свой параметр, модель и другие проверки в уровень сервиса, которые делают такие вещи, как проверка, чтобы убедиться, что вход действителен и что элемент для обновления существует в базе данных перед обновлением?
модели проверяют значения уровня поля ex. убедившись, что входной сигнал является действительным проверка на обязательные поля, возраст или диапазон дат и т. д. Службы должны выполнять любую необходимую проверку, которая требует проверки снаружи значения модели ex. Проверка того, что подарочный сертификат еще не был погашен, проверка свойств магазина, для которого предназначен подарочный сертификат).
может ли модель, репозиторий и пользовательский интерфейс выполнять вызовы на уровень сервиса, или это только для пользовательского интерфейса?
контроллеры и другие сервисы должны быть единственными, кто делает вызовы на уровень сервиса. Сервисы должны быть единственными, кто делает вызовы в репозитории.
- это уровень обслуживания должен быть все статические методы?
они могут быть, но легче сохранить и продлить, если они не. Изменения сущностей и добавление/удаление подклассы легче изменить, если есть 1 в лицо / подкласс.
каков был бы типичный способ вызова уровня сервиса из пользовательского интерфейса?
некоторые примеры контроллеров, вызывающих уровень сервиса:
giftCertificateService.GetEntity(giftCertificateId); (which in turn is just a call to the giftCertificateRepository.GetEntity(giftCertificateId) giftCertificateService.Redeem(giftCertificate);какие проверки должны быть включены модель против уровня сервиса?
уже ответил выше.
обновление
поскольку вы используете веб-формы, может быть немного сложнее понять некоторые концепции, но все, что я упомянул, применимо, поскольку то, что я описываю, является общей парадигмой MVC. ADO.NET для доступа к данным не имеет значения, так как доступ к данным развязан через репозитории.
добавляю ли я те же (и, возможно, больше) свойства к сервис, как у меня на моей модели (сумма, код и т. д.) Или я только предлагаю методы, которые принимают объекты GiftCertificate и прямые параметры?
вам нужно посмотреть на службы как именно то, что их имя подразумевает - действия, которые могут вызывать контроллеры. Вам не понадобятся свойства, определенные в вашей модели, поскольку они уже доступны в модели.
Я создаю экземпляр по умолчанию объекта GiftCertificate при вызове конструктора службы или просто создавать новые по мере необходимости (например, для методов проверки в службе, которые должны вызывать методы проверки в сущности? Кроме того, тот же вопрос о создании экземпляра репозитория по умолчанию...?
контроллеры и службы должны иметь частные поля для служб и репозиториев соответственно. Вы не должны создавать экземпляры для каждого действия / метода.
Я знаю, что я предоставляю функциональность РЕПО через сервис, я также предоставляю методы от сущности также (например, IsValidCode и т. д.)?
не слишком уверен, что вы имеете в виду здесь. Если службы возвращают сущности, то эти методы для сущностей уже доступны. Если они возвращают DTO, то это означает, что вы заинтересованы только в определенной информации.
для проверки я могу понять, почему вы немного обеспокоены, так как проверка выполняется непосредственно на модели и других типах проверки, выполняемых в службах. Эмпирическое правило, которое я использовал, заключается в том, что если проверка требует вызовов к БД, то это должно быть сделано в сервисном слое.
это нормально для пользовательского интерфейса, чтобы просто создать новый объект GiftCertificate непосредственно без прохождения службы (например, для вызова методов проверки параметров из сущности). Если нет,то как его обеспечить?
на уровне пользовательского интерфейса, когда я хочу создать новый подарочный сертификат, я вызываю проверку модели / службы (например, IsValidExpirationDate и т. д.) непосредственно из уровня пользовательского интерфейса или Я гидрата первый объект, а затем передать его для проверки и потом возвращают некое резюме проверки обратно в пользовательский интерфейс?
для этих 2 вопросов давайте рассмотрим сценарий:
пользователь вводит информацию для создания нового сертификата и представляет. Существует проверка уровня поля, так что если текстовое поле имеет значение null или если сумма отрицательна он выдает ошибку проверки. Предполагая, что все поля действительны, контроллер вызовет службу
gcService.Save(gc).служба проверит другую бизнес-логику, например, если магазин уже выдал слишком много подарочных сертификатов. Он либо возвращает перечисление для состояния, если есть несколько кодов ошибок, либо выдает исключение с информацией об ошибке.
наконец, служба вызывает
gcRepository.Save(gc).
вам не нужно создавать репозиторий для каждой сущности,подробнее об этом читайте тут,
обычно один определяет репозиторий на агрегат в домене. То есть: мы у вас нет репозитория для каждой сущности! Если мы смотрим на простой ввод заказа система порядок сущностей может быть следующим корень агрегата порядка. Таким образом мы будет иметь репозиторий заказов.
должна ли быть одна служба в репозитории? - > Не всегда, как вы можете использовать несколько репозиториев в одном сервисе.
сервис создает экземпляр модели, репозиторий никогда не будет взаимодействовать с моделью, фактически он возвращает сущность, которую модель будет использовать впоследствии.
обработка ввода / диапазона и т. д. вид проверки на уровне пользовательского интерфейса(u может использовать javascript или любую другую библиотеку), и пусть службы обрабатывают только бизнес-аспекты. Вы можете получить преимущества атрибутов, которые будут делать тот же.
UI->Service - >Repository, если репозиторий вызывает службу, чем thr должно быть что-то не так IMO.
Вы изменения в коде
разделите модель и репозитории.
public class GiftCertificateModel { } public class GiftCertificateRepository { //Remove Model related code from here, and just put ONLY database specific code here, (no business logic also). Common methods would be Get, GetById, Insert, Update etc. Since essence of Repository is to have common CRUD logic at one place soyou don't have to write entity specific code. You will create entity specific repository in rare cases, also by deriving base repository. } public class GiftCertificateService() { //Create Model instance here // Use repository to fill the model (Mapper) }
вы можете создать сервис под названием GiftCertificateService.
таким образом, вы будете координировать любую задачу, которая не относится к ответственности GiftCertificateModel в его службе. (Не путать со службой WCF).
служба будет управлять всеми задачами, поэтому ваш пользовательский интерфейс (или любой другой вызывающий объект) будет использовать методы, определенные в службе.
затем служба вызовет методы на модели, использует репозиторий, создает сделок и т. д.
например. (на основе примера кода, который вы предоставили):
public class GiftCertificateService { public void CreateCertificate() { //Do whatever needs to create a certificate. GiftCertificateRepository gcRepo = new GiftCertificateRepository(); GiftCertificateModel gc = gcRepo.CreateNew(); gc.Amount = 10.00M; gc.ExpirationDate = DateTime.Today.AddMonths(12); gc.Notes = "Test GC"; gcRepo.Save(gc); } }пользовательский интерфейс вызовет метод CreateCertificate (передавая Аргументы и т. д.), и метод также может возвращать что-то.
Примечание: Если вы хотите, чтобы класс действовал на пользовательский интерфейс, хотя затем создайте класс контроллера (если вы делаете MVC) или класс презентатора (если вы делаете MVVM и не хотите помещать все внутри ViewModel) и используйте GiftCertificateService из этого класса.
Comments