การแมปเอนทิตีเดียวกันกับตารางที่แตกต่างกัน


9

ความรู้เกี่ยวกับโดเมน

ฉันกำลังเขียนซอฟต์แวร์ POS (จุดขาย) ที่อนุญาตให้ชำระค่าสินค้าหรือคืนเงินได้ เมื่อชำระเงินหรือคืนเงินหนึ่งต้องระบุการโอนเงินที่หมายถึงการใช้: เงินสด EFT (~ = บัตรเครดิต) บัตรสะสมคะแนนบัตรกำนัล ฯลฯ

การโอนเงินหมายถึงชุดค่าที่แน่นอนและเป็นที่รู้จัก (ชนิดของ enum)

ส่วนที่ยุ่งยากคือฉันต้องสามารถจัดเก็บชุดย่อยที่กำหนดเองของวิธีการเหล่านี้สำหรับการชำระเงินและการคืนเงิน (ทั้งสองชุดอาจแตกต่างกัน) ในเครื่อง 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...
}

สาเหตุที่ไม่ใช่ "enum ธรรมดา" ก็คือมีพฤติกรรมบางอย่างที่อยู่ในชั้นเรียนเหล่านี้ ฉันต้องประกาศคลาสในที่สาธารณะ (แทนส่วนตัว) เพื่ออ้างอิงในการแม็พ FluentNHibernate (ดูด้านล่าง)

วิธีการใช้งาน

ทั้งการชำระเงินและการคืนเงินหมายถึงการจัดเก็บหรือดึงข้อมูลใน / จากฐานข้อมูลเป็นชุดเสมอ พวกเขาเป็นชุดที่แตกต่างกันสองชุดแม้ว่าค่าบางอย่างในทั้งสองชุดอาจเหมือนกัน

ใช้กรณีที่ 1: กำหนดวิธีการชำระเงิน / คืนเงินชุดใหม่

  • ลบวิธีการชำระเงิน / คืนเงินที่มีอยู่ทั้งหมด
  • ใส่อันใหม่

ใช้กรณีที่ 2: เรียกวิธีการชำระเงิน / คืนเงินทั้งหมด

  • รับชุดของการชำระเงิน / คืนเงินที่เก็บไว้ทั้งหมดหมายถึง

ปัญหา

ฉันติดอยู่กับการออกแบบปัจจุบันของฉันในด้านความเพียร ฉันใช้ NHibernate (กับ FluentNHibernate เพื่อประกาศแผนที่ชั้นเรียน) และฉันไม่สามารถหาวิธีทำแผนที่กับ DB schema ที่ถูกต้องได้

ฉันพบว่าเป็นไปได้ที่จะแมปคลาสหลาย ๆ ครั้งโดยใช้เอนทิตีชื่อแต่ฉันไม่แน่ใจว่ามันเป็นไปได้กับคลาสย่อย

สิ่งที่ฉันยังไม่พร้อมที่จะทำคือการเปลี่ยน MoneyTransferMean API สาธารณะเพื่อให้สามารถคงอยู่ได้ (ตัวอย่างเช่นการเพิ่ม a bool isRefundเพื่อแยกความแตกต่างระหว่างสอง) อย่างไรก็ตามการเพิ่มฟิลด์ discriminator ส่วนตัวบางส่วนหรือดังนั้นก็โอเค

การทำแผนที่ปัจจุบันของฉัน:

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แต่นำไปสู่การนี้ผมที่จะมีข้อยกเว้น

ฉันพยายามทำการแมปคลาสย่อยซ้ำ แต่ฉันไม่สามารถระบุ "การแมปหลัก" ซึ่งทำให้ฉันมีข้อยกเว้นเช่นเดียวกับข้างต้น

คำถาม

วิธีแก้ไขมีอยู่เพื่อคงอยู่ของโดเมนปัจจุบันของฉัน

ถ้าไม่ได้สิ่งที่เป็น refactor ที่เล็กที่สุดที่ฉันต้องดำเนินการกับหน่วยงานของฉันเพื่อให้พวกเขาคงอยู่กับ 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คุณสมบัติก็ยอดเยี่ยม
Amit Joshi

1
ทำไมคุณต้องการจัดเก็บวิธีการชำระเงินเหล่านั้นในฐานข้อมูล รัฐคืออะไรนอกเหนือจากชื่อ?
berhalak

@AmitJoshi ในขณะที่การเปลี่ยนแปลงเล็กน้อยสามารถแก้ไขปัญหา (บนพื้นผิว) ฉันต้องการหลีกเลี่ยงการเพิ่มตรรกะที่ไม่เกี่ยวข้องกับธุรกิจในโดเมนของฉัน
เห็น

@berhalak แน่นอนว่าการจัดเก็บเหล่านี้ในฐานข้อมูลนั้นดูไม่น่าเชื่อถือเลย อย่างไรก็ตามนี่คือข้อกำหนดจากโครงการที่รัฐทั้งหมดจะอยู่ในฐานข้อมูล
เห็น

คำตอบ:


0

ทำไมคุณไม่สร้างเอนทิตีเดียวMoneyTransferMeanพร้อมคุณสมบัติทั่วไป (ฟิลด์) ทั้งหมดและเพียงเพิ่ม 2 ฟิลด์พิเศษ (บูลีน) เพื่อตรวจสอบว่า MoneyTransferMean นั้นเป็นการชำระเงินหรือคืนเงินหรือทั้งสองอย่าง ???? คงอยู่หรือไม่

นอกจากนี้ยังสามารถทำได้ด้วย Entity พิเศษด้วย Id (PK) เพิ่มเขตข้อมูลพิเศษเดียวกันความสัมพันธ์จะเป็น 1: 1 กับ MoneyTransferMean น่าเกลียดฉันรู้ แต่ควรใช้งานได้


ฉันไม่ต้องการเพิ่มความซับซ้อนที่ไม่เกี่ยวข้องกับโดเมนในโครงการโดเมนของฉัน (เช่นการเพิ่มบูลีนซึ่งจำเป็นต้องใช้ภายหลัง / ถ้าจำเป็น) นอกจากนี้ฉันไม่ต้องการให้คนที่จะใช้คลาสเหล่านี้ทำผิดพลาด (โดยลืมตรวจสอบบูลีนและคิดว่าแต่ละค่าคือเงินคืนหมายถึงตัวอย่าง) มันคือทั้งหมดที่เกี่ยวกับความชัดเจน
เห็น

0

ฉันต้องการที่สองและเพิ่มในสิ่งที่ @ DEVX75 แนะนำในประเภทการทำธุรกรรมของคุณที่อธิบายแนวคิดเดียวกันเป็นหลักแม้ว่าหนึ่งในนั้นจะเป็น + ve ในขณะที่อีกประเภทหนึ่งคือ -ve ฉันอาจเพิ่มฟิลด์บูลีนเพียงฟิลด์เดียวและมีบันทึกแยกต่างหากเพื่อแยกแยะการคืนเงินจากการชำระ

สมมติว่าคุณมี UID และไม่ได้ใช้ชื่อป้ายกำกับหมายถึงเป็น ID คุณสามารถอนุญาตให้มีชื่อซ้ำกันสำหรับวิธีการและรวมถึงรายการเงินสดสองรายการเช่น:

โพสต์, ป้ายกำกับ, IsRefund

1, เงินสด, เท็จ

2, เงินสดจริง

3, คูปอง, เท็จ

4, คูปอง, จริง

จากนั้นคุณสามารถรับสิ่งต่อไปนี้:

ประเภทธุรกรรม = MoneyTransferMean.IsRefund? "คืนเงิน": "การชำระเงิน"

มูลค่าการทำธุรกรรม = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1: MoneyTransfer.amount

ด้วยวิธีนี้ถ้าในการทำธุรกรรมของคุณคุณได้อ้างถึง MoneyTransferMean.UID = 2 คุณจะรู้ว่านั่นคือการคืนเงินเป็นเงินสดแทนที่จะรู้ว่ามันเป็นประเภทธุรกรรมที่อาจเป็นการคืนเงินหรือการจ่ายเงินสด


พึงสังเกตว่าเพิ่งทราบว่าคุณไม่ต้องการ / ไม่สามารถแก้ไข API สาธารณะได้ ขออภัย / เพิกเฉยคำตอบของฉันแม้ว่าฉันจะทิ้งไว้เพราะบางทีมันอาจจะเป็นประโยชน์สำหรับผู้อื่นที่มีปัญหา / การใช้งานที่คล้ายกัน
FrugalTPH

0

สุดท้ายผมตัดสินใจที่จะแก้ปัญหาโดยการทำซ้ำนิติบุคคลของฉันMoneyTransferMeanเป็นสองหน่วยงานและPaymentMeanRefundMean

แม้ว่าจะคล้ายกันในการดำเนินการความแตกต่างระหว่างสองหน่วยงานมีความสมเหตุสมผลในธุรกิจและเป็นทางออกที่แย่ที่สุดสำหรับฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.