ORM и слои

Большинство методов должны выполнять одну задачу.

5
задан Adam Lassek 28 May 2009 в 22:51
поделиться

5 ответов

Вам кажется, что вам не хватает концепции IoC / DI (то есть инверсии управления / внедрения зависимостей). Вместо использования статических методов каждый из ваших слоев должен зависеть только от интерфейса следующего уровня с фактическим экземпляром, введенным в конструктор. Вы можете называть свой DL репозиторием, поставщиком или чем-то еще, если это чистая абстракция базового механизма сохранения.

Что касается объектов, которые представляют сущности (грубо отображаемые в таблицы), я настоятельно не рекомендую иметь два набора объектов (одна зависит от базы данных, а другая нет). Для них нормально ссылаться на все три уровня, если они являются POCO (они действительно не должны знать, что они сохраняются), или даже DTO (чистые структуры без какого-либо поведения). Создание их DTO лучше подходит для вашей концепции BL,

2
ответ дан 14 December 2019 в 19:23
поделиться

, который разбросан повсюду и напоминает мне о моих первых набегах на орм и DDD. Я лично использую основные объекты домена, объекты обмена сообщениями, обработчики сообщений и репозитории. Итак, мой пользовательский интерфейс отправляет сообщение обработчику, который, в свою очередь, увлажняет мои объекты через репозитории и выполняет бизнес-логику в этом доменном объекте. Я использую NHibernate для доступа к данным и FluentNHibernate для типизированной привязки, а не бесполезную идиотскую конфигурацию .hbm.

Таким образом, обмен сообщениями - это все, что совместно используется моим пользовательским интерфейсом и моими обработчиками, и все BL находятся в домене.

Я знаю, что, возможно, я подвергся наказанию за свое объяснение, если не ясно, я буду защищаться позже.

Лично я не большой поклонник объектов, генерируемых кодом.

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

[Serializable]
public class AddMediaCategoryRequest : IRequest<AddMediaCategoryResponse>
{
    private readonly Guid _parentCategory;
    private readonly string _label;
    private readonly string _description;

    public AddMediaCategoryRequest(Guid parentCategory, string label, string description)
    {
        _parentCategory = parentCategory;
        _description = description;
        _label = label;
    }

    public string Description
    {
        get { return _description; }
    }

    public string Label
    {
        get { return _label; }
    }

    public Guid ParentCategory
    {
        get { return _parentCategory; }
    }
}

[Serializable]
public class AddMediaCategoryResponse : Response 
{
    public Guid ID;
}


public interface IRequest<T> : IRequest where T : Response, new() {}


[Serializable]
public class Response
{
    protected bool _success;
    private string _failureMessage = "This is the default error message.  If a failure has been reported, it should have overwritten this message.";
    private Exception _exception;

    public Response()
    {
        _success = false;
    }

    public Response(bool success)
    {
        _success = success;
    }

    public Response(string failureMessage)
    {
        _failureMessage = failureMessage;
    }

    public Response(string failureMessage, Exception exception)
    {
        _failureMessage = failureMessage;
        _exception = exception;
    }

    public bool Success
    {
        get { return _success; }
    }

    public string FailureMessage
    {
        get { return _failureMessage; }
    }

    public Exception Exception
    {
        get { return _exception; }
    }

    public void Failed(string failureMessage)
    {
        _success = false;
        _failureMessage = failureMessage;
    }

    public void Failed(string failureMessage, Exception exception)
    {
        _success = false;
        _failureMessage = failureMessage;
        _exception = exception;
    }
}


public class AddMediaCategoryRequestHandler : IRequestHandler<AddMediaCategoryRequest,AddMediaCategoryResponse>
{
    private readonly IMediaCategoryRepository _mediaCategoryRepository;
    public AddMediaCategoryRequestHandler(IMediaCategoryRepository mediaCategoryRepository)
    {
        _mediaCategoryRepository = mediaCategoryRepository;
    }

    public AddMediaCategoryResponse HandleRequest(AddMediaCategoryRequest request)
    {
        MediaCategory parentCategory = null;
        MediaCategory mediaCategory = new MediaCategory(request.Description, request.Label,false);
        Guid id = _mediaCategoryRepository.Save(mediaCategory);
        if(request.ParentCategory!=Guid.Empty)
        {
            parentCategory = _mediaCategoryRepository.Get(request.ParentCategory);
            parentCategory.AddCategoryTo(mediaCategory);
        }
        AddMediaCategoryResponse response = new AddMediaCategoryResponse();
        response.ID = id;
        return response;
    }
}

Я знаю, что это продолжается и продолжается, но эта базовая система мне очень хорошо послужила в прошлом году

вы можете увидеть, что обработчик, чем позволяет объекту домена обрабатывать логику, специфичную для домена

2
ответ дан 14 December 2019 в 19:23
поделиться

Попробуйте централизовать весь доступ к данным с помощью шаблона репозитория. Что касается ваших сущностей, вы можете попробовать реализовать какой-то слой перевода, который будет отображать ваши сущности, чтобы он не сломал ваше приложение. Это временно и позволит вам медленно реорганизовать ваш код.

очевидно, что я не знаю полного объема вашей кодовой базы, поэтому подумайте о боли и выгодах.

0
ответ дан 14 December 2019 в 19:23
поделиться

Только мое мнение, YMMV.

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

  1. Это должно упростить вещи или, в худшем случае, не усложнять их.

  2. Это не должно увеличивать связь или уменьшать связность.

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

Мое собственное восприятие ценности этого нового материала заключается в том, что он помогает разработчику сдвинуть границу между DL и BL в немного более абстрактная территория. DL больше похож на необработанные таблицы, а на объекты. Вот и все. (Я обычно очень много работаю, чтобы сделать это в любом случае с немного более тяжелым SQL и хранимыми процедурами, но я m, вероятно, удобнее с SQL, чем в среднем). Но если LINQ и ORM еще не помогают вам в этом, я бы сказал, продолжайте, но это то, где конец туннеля; упрощение и немного смещение границы абстракции.

0
ответ дан 14 December 2019 в 19:23
поделиться

Вероятно, это слишком косвенный ответ, но в прошлом году я боролся с такого рода вопросами в мире Java и нашел Паттерны архитектуры корпоративных приложений Мартина Фаулера весьма полезными ( также см. его каталог образцов ). Многие шаблоны связаны с теми же проблемами, с которыми вы боретесь. Все они красиво абстрактны и помогли мне организовать мое мышление, чтобы увидеть проблему на более высоком уровне.

Я выбрал подход, в котором для инкапсуляции нашего взаимодействия с базой данных использовался преобразователь iBatis SQL. (Устройство сопоставления SQL управляет моделью данных языка программирования из таблиц SQL, тогда как ORM, как ваша, работает наоборот.) Сопоставитель SQL возвращает списки и иерархии объектов передачи данных, каждый из которых представляет собой строку некоторого результата запроса. Параметры запросов (а также вставки, обновления, удаления) также передаются как DTO. Уровень BL выполняет вызовы SQL Mapper (запускает этот запрос, выполняет эту вставку и т.д.) и передает DTO. DTO переходят на уровень представления (UI), где они управляют механизмами расширения шаблона, которые генерируют представления данных XHTML, XML и JSON. Итак, для нас единственной зависимостью DL, которая перетекала в пользовательский интерфейс, был набор DTO, но они сделали пользовательский интерфейс намного более упорядоченным, чем передача неупакованных значений полей.

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

Edit: @Ciel, Вы совершенно правы, экземпляр DTO - это просто POCO (или в моем случай Java POJO). Персональный DTO может иметь поле first_name «Джим» и так далее. Каждый DTO в основном соответствует строке таблицы базы данных и представляет собой просто набор полей, не более того. Это означает, что он не связан тесно с DL и идеально подходит для перехода к пользовательскому интерфейсу. Фаулер говорит об этом на стр. 401 (неплохой первый шаблон, чтобы порезаться).

Сейчас я не использую ORM, который берет ваши объекты данных и создает базу данных. Я использую средство сопоставления SQL, которое представляет собой очень эффективный и удобный способ упаковки и выполнения запросов к базе данных в SQL. Сначала я разработал свой SQL (я знаю его довольно хорошо), затем я разработал свои DTO, а затем настроил свою конфигурацию iBatis, чтобы сказать, что "select * from Person, где personid = # personid #" должен вернуть мне список Java. объектов Person DTO. Я' Мы еще не использовали ORM (Hibernate, например, в мире Java), но с одним из них вы должны сначала создать свои объекты модели данных, и база данных будет построена на их основе.

Если ваши объекты модели данных имеют всевозможные надстройки, специфичные для ORM, тогда я понимаю, почему вам стоит дважды подумать, прежде чем раскрывать их на уровне пользовательского интерфейса. Но там вы можете создать интерфейс C #, который определяет только методы POCO get и set, и использовать их во всех ваших API, не относящихся к DL, а также создать класс реализации, в котором есть все специфичные для ORM вещи:

interface Person ...

class ORMPerson : Person ...

Тогда, если вы измените свой ORM позже, вы можете создать альтернативные реализации POCO:

class NewORMPerson : Person ...

, и это повлияет только на ваш код уровня DL, потому что ваш BL и код пользовательского интерфейса использует Person.

@Zvolkov (ниже) предлагает использовать этот подход "кодирования" к интерфейсам, а не к реализациям »до следующего уровня,

1
ответ дан 14 December 2019 в 19:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: