Как выполнить проверку дубликатов ключей, используя entlib (или DataAnnotations), MVC и шаблон репозитория - PullRequest
1 голос
/ 28 декабря 2010

У меня есть набор проектов ASP.NET 4, кульминацией которых является приложение MVC (3 RC2).В решении используются проверки Unity и EntLib для сквозного внедрения и проверки зависимостей.Оба прекрасно работают для внедрения репозитория и реализаций сервисного уровня.

Однако я не могу понять, как выполнить проверку дубликатов ключей.Например, когда пользователь регистрируется, мы хотим убедиться, что он не выберет идентификатор пользователя, который уже используется кем-то другим.Для этого типа проверки объект проверки должен иметь ссылку на репозиторий ... или каким-либо другим способом получить ссылку IQueryable / IEnumerable для проверки других строк, уже находящихся в БД.

У меня есть класс UserMetadata, в котором есть все установщики и получатели свойств для пользователя, а также все соответствующие атрибуты DataAnnotations и EntLib Validation.Существует также класс UserEntity, реализованный с использованием шаблонов EF4 POCO Entity Generator.UserEntity зависит от UserMetadata, потому что у него есть MetadataTypeAttribute.У меня также есть класс UserViewModel, который имеет точно такой же атрибут MetadataType.Таким образом, я могу применять одни и те же правила проверки через атрибуты как к сущности, так и к модели представления.

Нет никаких конкретных ссылок на классы репозитория вообще.Все репозитории вводятся с использованием Unity.Существует также сервисный уровень, который получает внедрение зависимости.В проекте MVC классы реализации уровня обслуживания вводятся в классы контроллера (классы контроллера содержат только ссылки на интерфейс уровня обслуживания).Затем Unity внедряет реализации репозитория в классы уровня обслуживания (классы обслуживания также содержат только ссылки на интерфейс).

Я экспериментировал с DataAnnotations CustomValidationAttribute в классе метаданных.Проблема заключается в том, что метод проверки должен быть статическим, и метод не может напрямую создать реализацию репозитория.Мой интерфейс репозитория - IRepository , и у меня есть только один единственный класс реализации репозитория, определенный как EntityRepository для всех объектов домена.Чтобы создать экземпляр хранилища в явном виде, мне нужно было бы сказать новый EntityRepository (), что привело бы к циклическому графу зависимостей:Я также попытался создать пользовательский EntLib Validator вместе с пользовательским атрибутом проверки.Здесь у меня нет той же проблемы со статическим методом.Я думаю, я мог бы заставить это работать, если бы я мог просто выяснить, как заставить Unity внедрить мой EntityRepository в класс валидатора ... что я не могу.Прямо сейчас весь код проверки находится в моей библиотеке классов метаданных, так как именно туда должен идти пользовательский атрибут проверки.

Есть какие-нибудь идеи о том, как выполнять проверки, которые необходимо проверять в соответствии с текущим состоянием хранилища?Можно ли использовать Unity для внедрения зависимости в библиотеку классов более низкого уровня?

Ответы [ 3 ]

0 голосов
/ 29 декабря 2010

Я нашел решение, но не уверен, что оно лучшее.Мне это кажется грубой силой.

Первое, что я сделал, это объединил мои классы метаданных в тот же проект / библиотеку, что и мои классы сущностей.Поскольку мой интерфейс репозитория - IRepository , репозиторий необходимо было объявить как IRepository .Это разрешило круговую зависимость, о которой я говорил.Теперь у меня есть UserEntity [зависит от] UserMetadata [зависит от] DuplicateUserValidationAttribute [зависит от] DuplicateUserValidator [зависит от] UserEntity.Со всеми этими классами в одной библиотеке, хотя цикличность все еще существует, нет циклических зависимостей сборки.

Второе, что я сделал, - обернул мой IUnityContainer в одноэлементный файл и перенес его в мою библиотеку универсальных утилит (до того, как она существовала только в проекте MVC 3).

Затем в моем конструкторе DuplicateUserValidator я мог бы сделать следующее:

public class DuplicateUserValidator : Micrsoft.Practices.EnterpriseLibrary.Validation.Validator<string>
{
    public IRepository<UserEntity> UserRepository { get; set; }

    public DuplicateUserValidator(string tag)
        : base(string.Empty, tag)
    {
        IUnityContainer unity = UnityContainerSingleton.Get();
        this.UserRepository = unity.Resolve<IRepository<UserEntity>>() as IRepository<UserEntity>;
    }
}

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

0 голосов
/ 30 декабря 2010

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

Мне удалось сохранить класс UserMetadata в отдельной библиотеке от UserEntity.Вот как выглядит график зависимостей:

UserMetadata [зависит от] DuplicateUserValidationAttribute [зависит от] IDuplicateUserValidator

Фактический класс реализации DuplicateUserValidator находится в моем сервисном слое и выглядит примерно так:

public class DuplicateUserValidator : Validator<string>, IDuplicateUserValidator
{
    public DuplicateUserValidator()
        : base(null, null)
    {
    }

    [Dependency]
    public IRepository<UserEntity> UserRepository { get; set; }

    protected override string DefaultMessageTemplate
    {
        get { throw new NotImplementedException(); }
    }

    protected override void DoValidate(string stringToValidate, object currentTarget, string key, ValidationResults validationResults)
    {
        if (this.UserRepository == null)
            throw new InvalidOperationException("This should not happen");

        // actual code to perform validation...
    }
}

Хитрость заключается в том, что атрибут DuplicateUserValidatorAttribute не зависит от DuplicateUserValidator:

public class DuplicateUserValidatorAttribute : ValidatorAttribute
{
    protected override Validator DoCreateValidator(Type targetType)
    {
        var validator = Unity.Container.Resolve<IDuplicateUserValidator>() as Validator;
        validator.Tag = Tag;
        validator.MessageTemplate = GetMessageTemplate();
        return validator;
    }

}

Все, что мне нужно было сделать, это добавить сопоставление в конфигурацию Unity.Когда синглтон разрешает IDuplicateUserValidator, он внедряет мой класс реализации из уровня обслуживания, сохраняя атрибут [Dependency] в свойстве UserRepository.

0 голосов
/ 29 декабря 2010

Сделайте это в базе данных. Это единственное решение, которое может быть по-настоящему безопасным для нескольких пользователей.

...