Где должен быть мой код для вставки сущности, которая требует создания отношений перед сохранением? - PullRequest
2 голосов
/ 14 марта 2012

Ситуация: я использую LinqToSql (может считаться нерелевантным) для своего «уровня персистентности» и пытаюсь решить некоторые архитектурные проблемы, связанные с тем, куда должна идти определенная логика, связанная с бизнесом.

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

Моей первой попыткой было поместить весь этот джаз в класс OrderService. Затем я попытался включить его в свой DataContext, используя частичный метод:

partial void InsertOrder(Order instance)
{
        var productKeys = this.ProductKeys
            .Where(x => x.DeleteDate == null && x.Order == null && !x.Issued)
            .Take(instance.NumberOfProductKeys);

        if (productKeys.Count() != instance.NumberOfProductKeys)
            throw new NotSupportedException("There needs to be more product keys in the database.");

        instance.ProductKeys.AddRange(productKeys);

        this.ExecuteDynamicInsert(instance);
}

Несмотря на то, что это не работает должным образом (ключи продукта никогда не связаны с заказом), я чувствую, что это убирает логику из моей бизнес-сферы и выталкивает ее на мой «уровень постоянства». Я также думал о том, чтобы поместить его в класс OrderService, но чувствовал, что он также просто забрал логику у сущностей домена и привел к скрипту транзакции. Введение фабрики заказов просто обходит проблему: данные и логика снова разделены.

Итак, мой вопрос заключается в следующем: чтобы избежать анемичной модели предметной области и, надо надеяться, иметь порядок, делающий что-то помимо прославленной структуры данных, существует ли надлежащий способ интеграции этой логики в мою модель предметной области?

Лучшее решение, которое я нашел, - это поместить логику в класс Order и убедиться, что это было сделано в хуке проверки:

public partial class Order
{   
    public void AssociateWithProductKeys(WIIIPDataContext context)
    {
            var productKeys = context.ProductKeys
                .Where(x => x.DeleteDate == null && !x.Issued && x.Order == null && x.ProductType == ProductType)
                .Take(NumberOfProductKeys);

            if (productKeys.Count() != NumberOfProductKeys)
                throw new ValidationException("There needs to be more product keys in the database for product type: " + ProductType.Description);

            ProductKeys.AddRange(productKeys);

            foreach (ProductKey productKey in ProductKeys)
            {
                productKey.Issued = true;
            }
    }

    partial void OnValidate(ChangeAction action)
    {
        if (action == ChangeAction.Insert)
        {
            if (ProductType.Id == 3 && ProductKeys.Count() != 1)
                throw new ValidationException("Attempted to associated more than 1 product key with a CD version.");

            if (ProductKeys.Count() != NumberOfProductKeys)
                throw new ValidationException("Number of product keys doesn't match expected value");
        }
    }
}

Код потребления будет выглядеть так:

// The Unit of Work
using (var context = new MyDataContext())
{
    ...
    order.AssociateWithProductKeys(context);
    context.Orders.InsertOnSubmit(order);
    context.SubmitChanges();
}

== Обновление 29.03.2012 ==

Я принял шаблон команды / запроса при использовании LinqToSQL (и веб-форм) и больше не использую сущности, созданные LinqToSql DataContext, как нечто большее, чем отображение в мое хранилище данных. Все мои правила и все, что не входит в объекты команд, делают их, в некотором смысле, настоящим ядром приложения.

Ответы [ 2 ]

0 голосов
/ 14 марта 2012

Я использую LinqToSql (может считаться неуместным)

Я бы не стал считать это неуместным.

Не обращая внимания на обсуждение вопроса о том, является ли LINQ-to-SQL - это «реальный» ORM, я считаю, что все ORM (и в частности LINQ-to-SQL) очень предписывают то, как они хотят, чтобы вы их использовали.Придерживайтесь их предпочтительного образца, и все просто.Структурируйте свой код по своему выбору, и вы рискуете попасть в мир боли.

В этом случае LINQ-to-SQL работает лучше всего, когда он включает в себя как доступ к данным, так и логику (тесно связанную).Это ужасная практика, если у вас есть что-то кроме очень маленького проекта, и это приведет к отладке ночных кошмаров, но если вы попытаетесь разделить доступ к данным и логику, вы столкнетесь с некоторыми общими проблемами.

Рекомендация Microsoft -что DataContext должен быть недолговечным объектом, используемым для единицы работы.Этот подход не работает должным образом из-за «присоединенной» / «отсоединенной» модели, которую использует LINQ-to-SQL.Существуют десятки веб-сайтов, предлагающих взломать «отсоединение через сериализацию», что, на мой взгляд, ужасно.

Кроме того, модель ORM подходит для объектов данных, а не для полнофункциональных инкапсулированных объектов.DataContext необходимо поддерживать отношения между объектами, поэтому если они сами будут нести ответственность за себя, это может привести к более поздним головным болям.

Хотя мне нравится LINQ-to-SQL и я использовал его в ряде проектовЯ не могу порекомендовать отличный шаблон, и активно рекомендую против любого объектно-ориентированного шаблона на уровне данных.Забудьте то, что вы знаете, и вместо этого попробуйте написать простой в обслуживании слой данных.По моему опыту, разделение вашей логики и доступа к данным на основе строгих правил проектирования в дальнейшем приведет к значительным проблемам с этим инструментарием.

0 голосов
/ 14 марта 2012

Клиент передает заказ в Business Logic Layer (BLL). BLL вызывает метод DAL, чтобы получить n ключей продукта. DAL не реализует никакой логики, он просто получает n ключей. Затем BLL реагирует на то, что предоставил DAL. Если ключей достаточно, BLL связывает эти ключи с заказом и возвращает. Если ключей недостаточно, BLL не связывает ключи с заказом и выдает исключение. Затем клиент предоставляет правильное сообщение интерфейса пользователя на основе того, что вернул логический уровень.

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

Это помогает?

...