Дизайн ответа службы WCF на основе группировки c # - PullRequest
0 голосов
/ 08 декабря 2018

Мне нужна помощь с дизайном моей службы WCF.У меня есть метод, который возвращает Products из базы данных.В пользовательском интерфейсе у меня есть следующие опции для группировки продуктов:

  1. Нет / Группировка по умолчанию: возвращает список всех Products.

  2. Группировка производителей: возвращает список всех Products в зависимости от конкретного производителя.

  3. Налогооблагаемая группировка: возвращает список всех Products, которые подлежат налогообложению.

Ниже приведена вся структура моего ответа:

<ResponseStruct>
  <!-- Grouping is done on product-->
    <ProductList>
        <Product>
            <Name></Name>
            <Taxability>
                <Value></Value>
            </Taxability>
            <ManufacturerList>
                <Manufacturer>
                    <Name></Name>
                    <City></City>
                </Manufacturer>
                <Manufacturer>
                    <Name></Name>
                    <City></City>
                </Manufacturer>
            </ManufacturerList>
        </Product>
        <Product>
            <Name></Name>
            <Taxability>
                <Value></Value>
            </Taxability>
            <ManufacturerList>
                <Manufacturer>
                    <Name></Name>
                    <City></City>
                </Manufacturer>
                <Manufacturer>
                    <Name></Name>
                    <City></City>
                </Manufacturer>
            </ManufacturerList>
        </Product>
    </ProductList>

  <!-- Grouping is done on taxability of product-->
    <TaxabilityList>
        <Taxability>
            <Value></Value>
            <ProductList>
                <Product>
                    <Name></Name>
                    <ManufacturerList>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                    </ManufacturerList>
                </Product>
                <Product>
                    <Name></Name>
                    <ManufacturerList>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                    </ManufacturerList>
                </Product>
            </ProductList>
        </Taxability>
        <Taxability>
            <Value></Value>
            <ProductList>
                <Product>
                    <Name></Name>
                    <ManufacturerList>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                    </ManufacturerList>
                </Product>
                <Product>
                    <Name></Name>
                    <ManufacturerList>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                        <Manufacturer>
                            <Name></Name>
                            <City></City>
                        </Manufacturer>
                    </ManufacturerList>
                </Product>
            </ProductList>
        </Taxability>
    </TaxabilityList>

  <!-- Grouping is done on manufacterur-->
    <ManufacturerList>
        <Manufacturer>
            <Name></Name>
            <City></City>
            <ProductList>
                <Product>
                    <Name></Name>
                    <Taxability>
                        <Value></Value>
                    </Taxability>
                </Product>
                <Product>
                    <Name></Name>
                    <Taxability>
                        <Value></Value>
                    </Taxability>
                </Product>
            </ProductList>
        </Manufacturer>
        <Manufacturer>
            <Name></Name>
            <City></City>
            <ProductList>
                <Product>
                    <Name></Name>
                    <Taxability>
                        <Value></Value>
                    </Taxability>
                </Product>
                <Product>
                    <Name></Name>
                    <Taxability>
                        <Value></Value>
                    </Taxability>
                </Product>
            </ProductList>
        </Manufacturer>
    </ManufacturerList>
</ResponseStruct>

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

1.  Product
-   Name
-   Taxability
-   IList<Manufacturer>
2.  Taxability
-   Value
-   IList<Product>
3.  Manufacturer
-   Name
-   City
-   IList<Product>

Для варианта использования 1 (группировка по умолчанию) я оставляю закрытые теги ManufacturerList и TaxabilityList в ответ и заполняю объект ProductList только из базы данных.Для варианта использования 2 (группировка по производителю) я оставляю ProductList и TaxabilityList закрытыми в ответе и заполняю только объект ManufacturerList.

Пример ответа для варианта использования 3:

<ResponseStruct>
  <ProductList/>
  <ManufacturerList/>
  <TaxabilityList>...</TaxabilityList>
</ResponseStruct>

Нужна помощь:

Приведенный выше пример, который я создал, демонстрирует мою проблему.В действительности существует 5 вариантов группировки, и запрос ввода пользователя может иметь 2 уровня группировки (он может отправить его в массиве объекта группировки в запросе), и это приводит к 20 возможным форматам ответа.

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

Есть ли какой-то шаблон дизайна предмета или предложения, которые я могу прочитать, чтобы решить мою проблему?

Возможно, я подхожу к своей проблеме совершенно неправильно, поэтому буду признателен за любое решение.

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

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

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

interface MyService
{
    IList<Product> GetProducts();
    IList<Group<Product>> GetProductsGroupedByTaxability();
    IList<Group<Product>> GetProductsGroupedByManufacturer();
}

class Group<T>
{
    public String Name { get; set; }
    public IList<T> Items { get; set; }
}

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

interface MyService
{
    IList<Product> GetProducts();
    IList<Group<Product>> GetGroupedProducts(Field level1);
    IList<Group<IList<Group<Product>>> GetGroupedProducts(Field level1, Field level2);
}

enum Field { Manufacturer, Taxability }

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

<Groups>
    <Group>
        <Name>Massey Fergusson</Name>
        <Items>
            <Product>...</Product>
            <Product>...</Product>
            <Product>...</Product>
        </Items>
    </Group>
    <Group>
        <Name>John Deere</Name>
        <Items>
            <Product>...</Product>
            <Product>...</Product>
            <Product>...</Product>
        </Items>
    </Group>
</Groups>

и для двухуровневого:

<Groups>
    <Group>
        <Name>Massey Fergusson</Name>
        <Items>
            <Group>
                <Name>20%</Name>
                <Items>
                    <Product>...</Product>
                    <Product>...</Product>
                </Items>
            </Group>
            <Group>
                <Name>0%</Name>
                <Items>
                    <Product>...</Product>
                    <Product>...</Product>
                </Items>
            </Group>
        </Items>
    </Group>
    <Group>
        <Name>John Deere</Name>
        <Items>
            ...
        </Items>
    </Group>
</Groups>
0 голосов
/ 13 декабря 2018

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

Для начала,отныне все это GroupedCollection.Неважно, если пользователь ничего не выбрал, он все равно сгруппирован по .Наш класс GroupedCollection должен быть коллекцией коллекций.

Внутренняя коллекция будет иметь детали - внешняя коллекция будет просто коллекцией.

Итак, чтобы поместить это в код - это будет выглядеть следующим образом.

// This class is responsible from carrying information + items belonging to a single group.
public class SingleGroupCollection<N> : Collection<N>
    {
        //
        // The property bag is where you carry the per-group data.
        // Like your grouped-by Manufacturer <"name", "G. Manufacturer">
        // You should expose methods so you could retrieve all of its 
        // keys-values and display the group-specific data in your UI.

        Dictionary<string, string> PropertyBag;
        public SingleGroupCollection()
        {
             // Classic .Add() / .Remove() methods should work since 
             //   we inherit from a Collection.
        }
    }

Теперь, когда у нас есть класс SingleGroupCollection<Product> - нам нужно что-то, чтобы вместить все группы.Мы можем создать класс ниже:

/*
    This class will hold all of the data that you're tranferring across.
    Depending on the grouping type - which I've imagined to be an enum, 
    you can set to be only 1 group / vs multiple groups,
    fill the class as you see fit with the information that you've retrieved from the DB.
 */
public class GroupedCollection<N> : Collection<SingleGroupCollection<N>>
    {
        public GroupedCollection()
        {
            // default
        }

        public GroupedCollection(GroupingType[] type)
        {
            // set types
            // set collection
        }
    }

Таким образом, вы можете расширить / повторно использовать класс GroupedCollection, поддерживая несколько типов GroupingType и по-прежнему имея один тип ответа.

Что вы думаете?

...