Использование внедрения зависимостей в классе со свойством list‹interface‹T››, где T неизвестен

Пожалуйста, рассмотрите следующий сценарий...

У меня есть объекты для определения различных типов продуктов и свойств, необходимых для описания этого продукта (например, телевизор будет иметь разные атрибуты для духов и т. д.).

Таким образом, у меня есть концепция ProductType, которая имеет свойство List<> с элементами для разных полей (AttributeField<T>).

AttributeField<T> имеет свойство List<> для разных значений (AttributeValue<T>).

Затем продукт имеет ProductType для определения доступных полей (AttributeField<T>) и List<AttributeValue<?>> для значений для этого конкретного продукта.

Я пытаюсь реализовать эту концепцию на С#. У меня есть структура, определенная для интерфейсов и объектов, но я изо всех сил пытаюсь сопоставить объекты с помощью Fluent NHibernate, предположительно потому, что ProductType не является универсальным классом, но имеет универсальное свойство (List<AttributeField<T>>, где T может быть чем угодно).

Интерфейсы > IProductType

public interface IProductType
{
    Guid Id { get; set; }
    string Name { get; set; }
    List<IAttributeField> Fields { get; set; }
}

Интерфейсы > IAttributeField / IAttributeField

public interface IAttributeField
{
    Guid Id { get; set; }
    string Name { get; set; }
    IProductType ProductType { get; set; }
}

public interface IAttributeField<T> : IAttributeField
{
    Guid Id { get; set; }
    string Name { get; set; }
    List<IAttributeValue<T>> Values { get; set; }
    IProductType ProductType { get; set; }
}

Интерфейсы > IAttributeValue

public interface IAttributeValue<T>
{
    Guid Id { get; set; }
    T Value { get; set; }
    IAttributeField<T> Field { get; set; }
}

Классы > Тип продукта

public class ProductType : IProductType
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public List<IAttributeField> Fields { get; set; }
}

Классы > Поле атрибутов

public class AttributeField<T> : IAttributeField<T>
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public List<IAttributeValue<T>> Values { get; set; }
    public IProductType ProductType { get; set; }
}

Классы > Значение атрибута

public class AttributeValue<T> : IAttributeValue<T>
{
    public Guid Id { get; set; }
    public T Value { get; set; }
    public IAttributeField<T> Field { get; set; }
}

Я использую Fluent NHibernate для ORM с базой данных SQL 2008 и имею следующие классы сопоставления:

Классы > Сопоставление типов продуктов

public class ProductTypeMapping : ClassMap<IProductType>
{
    public ProductTypeMapping()
    {
        Not.LazyLoad();
        Id(x => x.Id).GeneratedBy.GuidNative();
        Map(x => x.Name).Length(50).Not.Nullable();
        HasMany(x => x.Fields).CollectionType<IAttributeField>();
    }
}

Классы > Сопоставление полей атрибутов

public class GenericAttributeFieldMapping : ClassMap<IAttributeField>
{
    public GenericAttributeFieldMapping()
    {
        Not.LazyLoad();
        Id(x => x.Id);
        Map(x => x.Name).Length(50).Not.Nullable();
        References(x => x.ProductType).Cascade.All();
    }
}

public class AttributeFieldMapping<T> : ClassMap<IAttributeField<T>>
{
    public AttributeFieldMapping()
    {
        Not.LazyLoad();
        Id(x => x.Id).GeneratedBy.GuidNative();
        Map(x => x.Name).Length(50).Not.Nullable();
        HasMany(x => x.Values).Cascade.AllDeleteOrphan();
        References(x => x.ProductType).Cascade.All();
    }
}

Классы > Сопоставление атрибутов и значений

public class AttributeValueMapping<T> : ClassMap<IAttributeValue<T>>
{
    public AttributeValueMapping()
    {
        Not.LazyLoad();
        Id(x => x.Id).GeneratedBy.GuidNative();
        Map(x => x.Value).CustomType<T>();
        References(x => x.Field).Cascade.All();
    }
}

Когда я пытаюсь выполнить модульное тестирование вышеуказанного с помощью new PersitenceSpecification<ProductType>, я получаю следующую ошибку:

Адаптер модульного тестирования вызвал исключение: тип не разрешен для члена «FluentNHibernate.Cfg.FluentConfigurationException, FluentNHibernate, Version=1.3.0.733, Culture=neutral, PublicKeyToken=8aa435e3cb308880»..

При дальнейшей отладке я получаю следующее сообщение об исключении:

Нет сохранятеля для: System.Collections.Generic.List`1[[Models.Interfaces.IAttributeField, Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

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

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


person John Askew    schedule 21.11.2013    source источник


Ответы (1)


Fluent NHibernate — это средство сопоставления объектных отношений и решение для сохраняемости. Это не контейнер для внедрения зависимостей.

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

Мне кажется, что вы пытаетесь создать объекты своего приложения с помощью Fluent NHibernate, а не просто полагаетесь на него для сохранения. Это, вероятно, приведет к очень сложному отображению как части ORM, что может привести к большому количеству классов отображения. Как указано здесь, вам нужен класс сопоставления для каждого конкретного типа в ваших дженериках: ‹TEntity› класс с FluentNHibernate Итак, это ваш пример, я думаю, вам понадобится по одному для каждого IAttributeField<T> и каждого IAttributeValue<T>

Я бы попытался максимально упростить классы сопоставления, чтобы они соответствовали вашей модели данных, и использовать уровень обслуживания с некоторыми фабриками или AutoMapper для создания объектов вашего приложения. Не всегда рекомендуется отделять ваши постоянные объекты от приложения (поскольку это может добавить ненужные слои и сложность — код Macaroni), но в такой ситуации кажется, что это может быть необходимо.

Как я уже сказал, начните с модели данных и лучше всего работайте вовне, и убедитесь, что вы понимаете, что Fluent NHibernate — это просто ORM со многими мощными функциями.

person Rob Stevenson-Leggett    schedule 21.11.2013