.NET ORM, объекты неизменяемых значений, структуры, конструкторы по умолчанию и свойства только для чтения

Я только начинаю работать с .NET ORM до такой степени, что даже не решил между Entity Framework и NHibernate. Но в обоих случаях я сталкиваюсь с проблемой, заключающейся в том, что они, кажется, хотят, чтобы я различными способами нарушил целостность моей модели предметной области, особенно в тонкостях проектирования объектов C #. Это один из нескольких вопросов по теме.


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

public class Foo
{
    private readonly string bar;
    public string Bar { return this.bar; }

    public Foo(string bar)
    {
        this.bar = bar;
    }
}

Похоже, что это не поддерживается NHibernate или Entity Framework. Им нужны конструкторы по умолчанию и public сеттеры; похоже, что даже private сеттеры (и конструкторы по умолчанию) работают (иногда?), потому что ORM могут использовать отражение.

Я полагаю, что могу обойти это, используя private сеттеры и private конструктор по умолчанию. По крайней мере, тогда публичный API не будет скомпрометирован. Просто я модифицирую все реализации своих классов, чтобы добавить неиспользуемые private конструкторы, и необходимость доверять future-Domenic, что он понимает private на моих установщиках, на самом деле означает «не звоните мне, кроме как в конструкторе». Уровень сохраняемости просачивается в мой объектный дизайн предметной области.

Это также кажется ненужным - почему ORM не может знать, что использовать конструктор, отличный от конструктора по умолчанию? Может быть, они могут это сделать, и я просто не нашел нужного сообщения в блоге, объясняющего, как это сделать.

Наконец, в некоторых случаях мои неизменяемые объекты значений действительно хорошо подходят (неизменяемые) типы значений, то есть structs. Я предполагаю, что это возможно, поскольку в базе данных поля моей структуры будут отображаться в той же строке, что и родительский объект. Вы можете подтвердить / опровергнуть? Это сообщение в блоге выглядит многообещающим, поскольку дает утвердительный ответ, но количество кода (что на самом деле характерно для рассматриваемого типа значения) ошеломляет.


Разочаровывает, что после нескольких лет чтения таких книг, как Effective C # или блогов, подобных блогам Эрика Липперта, в которых даются отличные советы о том, как создавать выразительные и пуленепробиваемые объекты C #, необходимость использования ORM заставляет меня бросать большая часть этих знаний за окном. Я надеюсь, что кто-то здесь сможет указать, в чем я ошибаюсь, - либо в моем понимании их возможностей, либо в моих размышлениях о моделировании предметной области и роли ORM.


person Domenic    schedule 19.03.2011    source источник
comment
У вас есть как минимум три вопроса, которые сводятся к тому, что мне не нравятся ORM, потому что они ставят под угрозу мой дизайн. ORM - это инструменты для решения конкретной проблемы. Если они вам не нравятся, зачем их использовать? Напишите свой собственный уровень доступа к данным с помощью ADO.NET. После нескольких месяцев набора шаблонного кода вы можете оценить компромиссы, которые вводят ORM. (Я сделал нечто подобное несколько лет назад; я не вернусь.)   -  person TrueWill    schedule 20.03.2011
comment
Да, это все связанные вопросы, которые возникают, когда я начинаю погружаться в ORM. Но я бы лучше разделил их на категории, которые помогают мне понять компромиссы в вопросах ORM. Я стремлюсь использовать ORM, поскольку, как вы говорите, доступ к данным в ADO.NET - безумный соус. Дело не в том, что они мне не нравятся, а в том, что я все еще просто узнаю о них и пытаюсь получить помощь, чтобы правильно настроить себя.   -  person Domenic    schedule 20.03.2011
comment
Например, если я читал сравнения EF и NHibernate, имея в виду такие вопросы, как, например, что приведет к меньшим компромиссам в моей модели предметной области? две структуры, основанные на функциях, зрелости, возможностях и т. д.   -  person Domenic    schedule 20.03.2011


Ответы (2)


Как отмечается в комментариях, вам придется пойти на некоторые компромиссы, когда / если вы примете ORM. На мой взгляд, следует помнить, что повышение производительности намного перевешивает «затраты» этих компромиссов.

Я действительно хотел указать вам (поскольку вы новичок в EF), что вы можете настроить шаблоны T4, которые генерируют сущности и контексты EF. Я думаю, если вы поиграете с этим, вы сможете сгладить большинство вещей, которые вам не нравятся.

person BrandonZeider    schedule 08.04.2011

Пользуясь многими ORM, я чувствую боль, потому что использование интерфейсов, абстракции и неизменяемых объектов не работает должным образом с большинством ORM. По этой и другим причинам я написал свою собственную около 8 лет назад, я обнаружил некоторые из этих проблем, используя мою собственную ORM, и нашел способы их решения. Я бы посмотрел на Micro ORM и увидел, что вы можете найти, их много, и они имеют богатый набор функций, а у многих меньше багажа.

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

    string sql = "Select * from simpleEntities";
    ISqlQuery query = _factory.CreateSqlQuery(sql, nameof(AbstractFactoryTests.ReadImmutableEntityItems));
    IList<IImmutableEntity> items = loader.ObtainItemsImmutable<IImmutableEntity>(query);

or:

    IList<ISqlQuery> queries = new List<ISqlQuery>();

    // Note, no register types needed here because of returnType parameter

    ISqlQuery s1 = _factory.CreateSqlQuery("Select * from Employee where EmployeeType=1", "LoadAbstract.ParallelLoadItems1", typeof(Employee));
    queries.Add(s1);
    ISqlQuery s2 = _factory.CreateSqlQuery("Select * from Employee where EmployeeType=2", "LoadAbstract.ParallelLoadItems2", typeof(Manager));
    queries.Add(s2);
    ISqlQuery s3 = _factory.CreateSqlQuery("Select * from Employee where EmployeeType=3", "LoadAbstract.ParallelLoadItems3", typeof(DistrictManager));
    queries.Add(s3);

     IList<IEmployee> data = loader.ParallelLoadAbstractItems<IEmployee>(_factory, queries);
person Eric Schneider    schedule 23.08.2020