Где разместить методы сохранения / предварительного сохранения в доменном объекте? - PullRequest
0 голосов
/ 15 сентября 2011

Я хочу применять некоторые правила каждый раз, когда объект домена сохраняется, но я не знаю, как лучше всего этого добиться. Как я понимаю, у меня есть два варианта: добавить метод сохранения к объекту домена или обработать правила перед сохранением на уровне приложения. Смотрите пример кода ниже:

using System;

namespace Test
{

    public interface IEmployeeDAL
    {
        void Save(Employee employee);
        Employee GetById(int id);
    }

    public class EmployeeDALStub : IEmployeeDAL
    {
        public void Save(Employee employee)
        {

        }

        public Employee GetById(int id)
        {
            return new Employee();
        }
    }

    public interface IPermissionChecker
    {
        bool IsAllowedToSave(string user);
    }

    public class PermissionCheckerStub : IPermissionChecker
    {
        public bool IsAllowedToSave(string user)
        {
            return false;
        }
    }

    public class Employee
    {
        public virtual IEmployeeDAL EmployeeDAL { get; set; }
        public virtual IPermissionChecker PermissionChecker { get; set; }

        public int Id { get; set; }
        public string Name { get; set; }

        public void Save()
        {
            if (PermissionChecker.IsAllowedToSave("the user"))  // Should this be called within EmployeeDAL?
                EmployeeDAL.Save(this);
            else
                throw new Exception("User not permitted to save.");
        }
    }

    public class ApplicationLayerOption1
    {
        public virtual IEmployeeDAL EmployeeDAL { get; set; }
        public virtual IPermissionChecker PermissionChecker { get; set; }

        public ApplicationLayerOption1()
        {
            //set dependencies
            EmployeeDAL = new EmployeeDALStub();
            PermissionChecker = new PermissionCheckerStub();
        }

        public void UnitOfWork()
        {
            Employee employee = EmployeeDAL.GetById(1);

            //set employee dependencies (it doesn't seem correct to set these in the DAL);
            employee.EmployeeDAL = EmployeeDAL;
            employee.PermissionChecker = PermissionChecker;

            //do something with the employee object
            //.....

            employee.Save();
        }
    }

    public class ApplicationLayerOption2
    {
        public virtual IEmployeeDAL EmployeeDAL { get; set; }
        public virtual IPermissionChecker PermissionChecker { get; set; }

        public ApplicationLayerOption2()
        {
            //set dependencies
            EmployeeDAL = new EmployeeDALStub();
            PermissionChecker = new PermissionCheckerStub();
        }

        public void UnitOfWork()
        {
            Employee employee = EmployeeDAL.GetById(1);

            //do something with the employee object
            //.....

            SaveEmployee(employee);
        }

        public void SaveEmployee(Employee employee)
        {
            if (PermissionChecker.IsAllowedToSave("the user"))  // Should this be called within EmployeeDAL?
                EmployeeDAL.Save(employee);
            else
                throw new Exception("User not permitted to save.");
        }
    }
}

Что вы делаете в этой ситуации?

Ответы [ 3 ]

0 голосов
/ 15 сентября 2011

Если бы мне пришлось выбирать, я бы выбрал второй вариант, чтобы мои объекты не были связаны с какой-либо инфраструктурой DAL и были полностью сфокусированы на логике домена.

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

Другая вещь, которую я бы изменил, - это уход от мышления «CRUD».Вы можете предоставить много подробных параметров безопасности, если вы защищаетесь от определенных команд / вариантов использования.Например, я сделал бы это:

public class MyApplicationService
{
    [RequiredCommand(EmployeeCommandNames.MakeEmployeeRedundant)]
    public MakeEmployeeRedundant(MakeEmployeeRedundantCommand command)
    {
        using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
        {
            Employee employee = _employeeRepository.GetById(command.EmployeeId);

            employee.MakeRedundant();

            _employeeRepository.Save();
        }
    }
}

public void AssertUserHasCorrectPermission(string requiredCommandName)
{
    if (!Thread.CurrentPrincipal.IsInRole(requiredCommandName))
        throw new SecurityException(string.Format("User does not have {0} command in their role", requiredCommandName));
}

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

Вот ссылка на то, как использовать единство для перехвата: http://litemedia.info/aop-in-net-with-unity-interception-model

0 голосов
/ 16 сентября 2011

Куда поместить методы сохранения / предварительного сохранения в объекте домена?

Объекты домена постоянно игнорируют DDD.Они не знают о том, что иногда их «замораживают», перевозят в какое-то хранилище, а затем восстанавливают.Они этого не замечают.Другими словами, доменные объекты всегда находятся в «действительном» и сохраняемом состоянии.

Разрешение также должно быть постоянным невежественным и основываться на домене и вездесущем языке, например:

Только пользователи из группы "Продажи" могут добавлять строки заказов в заказ в состоянии ожидания

В отличие от:

Только пользователи из группы продаж могут сохранить Заказать .

Код может выглядеть следующим образом:

internal class MyApplication {

    private IUserContext _userContext;
    private ICanCheckPermissions _permissionChecker;

    public void AddOrderLine(Product p, int quantity, Money price, ...) {

     if(!_permissionChecker.IsAllowedToAddOrderLines(_userContext.CurrentUser)) {
         throw new InvalidOperationException(
            "User X is not allowed to add order lines to an existing order");
     }

     // add order lines

    }
}
0 голосов
/ 15 сентября 2011

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

При первом подходе вы вводите DAL и валидацию в бизнес-объект. Где я мог бы поспорить, если внедрение валидатора в сущность может быть хорошей практикой, внедрение DAL в сущность организации, безусловно, не является хорошим практическим ИМХО (но я понимаю, что это всего лишь демонстрация, и в реальном проекте вы бы хотя бы используйте для этого сервисный локатор).

...