Отображение одной и той же сущности в разные таблицы

9

Немного знания предметной области

Я пишу POS (Point Of Sales) программное обеспечение, которое позволяет оплачивать товары или возвращать их. При оплате или возврате денег необходимо указать, какой денежный перевод означает использовать: наличные, EFT (~ = кредитная карта), карта лояльности, ваучер и т. Д.

Эти средства денежных переводов представляют собой конечный и известный набор значений (своего рода перечисление).

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

Например:

  • Доступные способы оплаты: наличные, EFT, карта лояльности, ваучер
  • Доступный возврат средств: наличные, ваучер

Текущее состояние реализации

Я решил реализовать концепцию перевода денег следующим образом:

public abstract class MoneyTransferMean : AggregateRoot
{
    public static readonly MoneyTransferMean Cash = new CashMoneyTransferMean();
    public static readonly MoneyTransferMean EFT = new EFTMoneyTransferMean();
    // and so on...

    //abstract method

    public class CashMoneyTransferMean : MoneyTransferMean
    {
        //impl of abstract method
    }

    public class EFTMoneyTransferMean : MoneyTransferMean
    {
        //impl of abstract method
    }

    //and so on...
}

Причина, по которой это не просто перечисление, заключается в том, что в этих классах существует некоторое поведение. Мне также пришлось объявить внутренние классы открытыми (а не закрытыми), чтобы ссылаться на них в отображении FluentNHibernate (см. Ниже).

Как это используется

Средства оплаты и возврата всегда хранятся или извлекаются в / из БД в виде набора. На самом деле это два разных набора, хотя некоторые значения внутри обоих наборов могут быть одинаковыми.

Вариант использования 1: определить новый набор средств оплаты / возврата

  • Удалить все существующие способы оплаты / возврата
  • Вставьте новые

Вариант использования 2: получить все средства оплаты / возврата

  • Получить коллекцию всех сохраненных средств оплаты / возврата

проблема

Я застрял с моим текущим дизайном на аспекте постоянства. Я использую NHibernate (с FluentNHibernate для объявления карт классов) и не могу найти способ сопоставить его с какой-либо действительной схемой БД.

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

Что я не готов сделать, так это изменить публичный API MoneyTransferMean, чтобы иметь возможность его сохранить (например, добавить bool isRefundразличие между ними). Однако добавление некоторого частного поля дискриминатора или все в порядке.

Мое текущее отображение:

public sealed class MoneyTransferMeanMap : ClassMap<MoneyTransferMean>
{
    public MoneyTransferMeanMap()
    {
        Id(Entity.Expressions<MoneyTransferMean>.Id);
        DiscriminateSubClassesOnColumn("Type")
            .Not.Nullable();
    }
}

public sealed class CashMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.CashMoneyTransferMean>
{
    public CashMoneyTransferMeanMap()
    {
        DiscriminatorValue("Cash");
    }
}

public sealed class EFTMoneyTransferMeanMap : SubclassMap<MoneyTransferMean.EFTMoneyTransferMean>
{
    public EFTMoneyTransferMeanMap()
    {
        DiscriminatorValue("EFT");
    }
}

//and so on...

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

Я попытался объявить два сопоставления, ссылающихся как MoneyTransferMeanна другую таблицу, так и на имя объекта, однако это приводит меня к исключению Duplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean.

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

Вопрос

Существует ли решение для сохранения моих текущих доменных сущностей?

Если нет, то какой наименьший рефакторинг я должен выполнить для своих сущностей, чтобы сделать их устойчивыми с помощью NHibnernate?

пятнистый
источник
1
What I'm not ready to do is to alter the MoneyTransferMean public API to be able to persist it (for example adding a bool isRefund to differentiate between the two).: Почему бы нет? Это простое и приятное изменение, которое должно решить вашу проблему. Вы можете сделать с тремя возможными значениями (хотя два и будет делать с дублированием записей или Flagтипа): Payment, Refund, Both. Если для вас boolподходят два значения, то собственность просто великолепна.
Амит Джоши
1
Почему вы хотите сохранить эти способы оплаты в базе данных? Какое там состояние, кроме названия?
берхалак
@AmitJoshi Хотя такое небольшое изменение может решить проблему (на первый взгляд), я хочу избегать добавления логики, не связанной с бизнесом, в мой домен.
Пятнистый
@berhalak Действительно, хранение их в базе данных выглядит немного неуклюжим. Однако это требование от проекта, чтобы все состояние было в базе данных.
Пятнистый

Ответы:

0

Почему бы вам не создать одну единственную сущность MoneyTransferMean со всеми общими свойствами (полями) и просто добавить 2 дополнительных поля (логических), чтобы определить, является ли этот MoneyTransferMean платёжным или возвратным, или и тем и другим ???? Сохранять это или нет.

Также это может быть сделано с дополнительным Entity с Id (PK), добавьте те же дополнительные поля, отношение будет 1: 1 с MoneyTransferMean. Ужасно, я знаю, но это должно работать.

DEVX75
источник
Я не хочу добавлять сложность, не связанную с доменом, в мой проект домена (например, добавление логического значения, для которого требуется последующее условие if / else). Также я не хочу, чтобы люди, которые будут использовать эти классы, делали ошибку (забывая проверять логическое значение и думая, что каждое значение, например, означает возврат). Все дело в явности.
Пятнистый
0

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

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

UID, Метка, IsRefund

1, наличные деньги, ложь

2, наличные деньги, правда

3, Ваучер, ложь

4, Ваучер, правда

Тогда вы можете легко получить следующее:

Тип транзакции = MoneyTransferMean.IsRefund? «Возврат»: «Оплата»

Стоимость транзакции = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1: MoneyTransfer.amount

Таким образом, если в своих транзакциях вы ссылались на MoneyTransferMean.UID = 2, вы знаете, что это денежное возмещение, а не знаете, что это тип транзакции, который может быть либо денежным, либо денежным.

FrugalTPH
источник
Ах, черт возьми, только что заметил, что вы сказали, что не хотите / не можете редактировать общедоступный API. Извините / игнорируйте мой ответ, хотя я оставлю его, так как, возможно, он будет полезен для других с подобной проблемой / вариантом использования.
FrugalTPH
0

Наконец, я решил решить эту проблему, дублируя мое лицо MoneyTransferMeanна два объекта PaymentMeanи RefundMean.

Несмотря на схожесть в реализации, различие между двумя объектами имеет смысл в бизнесе и было для меня наименее худшим решением.

пятнистый
источник