Зіставлення однієї сутності в різні таблиці


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 mapping (див. Нижче).

Як воно використовується

І засоби оплати, і кошти повернення завжди зберігаються або отримуються в / з БД як набір. Вони справді є двома різними наборами, хоча деякі значення всередині обох наборів можуть бути однаковими.

Використовуйте випадок 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 є або платежем, або поверненням, або обома ???? Зберігати це чи ні.

Також це можна зробити з додатковою суттю з Id (PK), додати ті самі додаткові поля, співвідношення було б 1: 1 з MoneyTransferMean. Потворне, я знаю, але це має працювати.


Я не хочу додавати складність, що не стосується домену в моєму проекті домену (наприклад, додавання булевих даних, для яких потрібно подальший if / else). Крім того, я не хочу, щоб люди, які будуть використовувати ці класи, помилялися (забувши перевірити булеву і подумавши, що кожне значення - це, наприклад, відшкодування). Вся справа в явності.
Виявлено

0

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

Якщо припустити, що ви маєте UID і не використовуєте назву мітки засобів як ідентифікатор, ви можете дозволити копіювати імена для засобів і включити дві записи готівки, наприклад:

UID, Label, IsRefund

1, Готівка, помилково

2, Готівка, правда

3, ваучер, хибний

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

Тоді ви можете легко отримати наступне:

Тип транзакції = MoneyTransferMean.IsRefund? "Відшкодування": "Оплата"

Значення транзакції = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1: MoneyTransfer.amount

Таким чином, якщо у ваших транзакціях ви посилалися на MoneyTransferMean.UID = 2, ви знаєте, що це повернення готівки, а не знати, що це тип транзакції, який може бути або поверненням грошових коштів, або грошовим платежем.


О, баггер, щойно помітив, ви сказали, що не хочете / не можете редагувати загальнодоступний API. Вибачте / ігноруйте мою відповідь, хоча я залишу її, як, можливо, вона буде корисною для інших, хто має аналогічні проблеми / використання.
FrugalTPH

0

Нарешті, я вирішив вирішити проблему, дублюючи свою сутність MoneyTransferMeanна дві сутності PaymentMeanта RefundMean.

Незважаючи на те, що це схоже в реалізації, відмінність між двома суб'єктами має сенс у бізнесі і було для мене найменш гіршим рішенням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.