Ánh xạ cùng một thực thể vào các bảng khác nhau


9

Một chút kiến ​​thức về miền

Tôi đang viết phần mềm POS (Điểm bán hàng) cho phép thanh toán hàng hóa hoặc hoàn tiền cho họ. Khi thanh toán hoặc hoàn trả, người ta cần chỉ định sử dụng chuyển tiền nào : tiền mặt, EFT (~ = thẻ tín dụng), thẻ khách hàng thân thiết, chứng từ, v.v.

Các phương tiện chuyển tiền này là một tập hợp các giá trị hữu hạn và đã biết (một loại enum).

Phần khó khăn là tôi cần có khả năng lưu trữ một tập hợp con tùy chỉnh của các phương tiện này cho cả thanh toán và hoàn tiền (hai bộ có thể khác nhau) trên thiết bị đầu cuối POS.

Ví dụ:

  • Có sẵn phương tiện thanh toán: Tiền mặt, EFT, Thẻ khách hàng thân thiết, Phiếu mua hàng
  • Hoàn trả có nghĩa là: Tiền mặt, Phiếu quà tặng

Hiện trạng thực hiện

Tôi chọn thực hiện khái niệm chuyển tiền có nghĩa như sau:

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...
}

Lý do nó không phải là "enum đơn giản" là có tồn tại một số hành vi bên trong các lớp này. Tôi cũng đã phải khai báo các lớp bên trong công khai (thay vì riêng tư) để tham chiếu chúng trong ánh xạ FluentNHibernate (xem bên dưới).

Nó được sử dụng như thế nào

Cả phương tiện thanh toán và hoàn trả luôn được lưu trữ hoặc truy xuất trong / từ DB dưới dạng tập hợp. Chúng thực sự là hai bộ riêng biệt mặc dù một số giá trị bên trong cả hai bộ có thể giống nhau.

Trường hợp sử dụng 1: xác định một nhóm phương tiện thanh toán / hoàn trả mới

  • Xóa tất cả các phương tiện thanh toán / hoàn trả hiện có
  • Chèn cái mới

Trường hợp sử dụng 2: lấy tất cả các phương tiện thanh toán / hoàn trả

  • Nhận một bộ sưu tập của tất cả các phương tiện thanh toán / hoàn trả được lưu trữ

Vấn đề

Tôi bị mắc kẹt với thiết kế hiện tại của tôi trên khía cạnh kiên trì. Tôi đang sử dụng NHibernate (với FluentNHibernate để khai báo các bản đồ lớp) và tôi không thể tìm cách ánh xạ nó tới một lược đồ DB hợp lệ.

Tôi thấy rằng có thể ánh xạ một lớp nhiều lần bằng tên thực thể tuy nhiên tôi không chắc chắn rằng nó có thể với các lớp con.

Điều tôi chưa sẵn sàng làm là thay đổi API công khai MoneyTransferMean để có thể duy trì nó (ví dụ: thêm một bool isRefundđể phân biệt giữa hai). Tuy nhiên, thêm một số lĩnh vực phân biệt đối xử tư nhân hoặc như vậy là ok.

Bản đồ hiện tại của tôi:

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...

Ánh xạ này biên dịch tuy nhiên nó chỉ tạo ra 1 bảng và tôi không thể phân biệt giữa thanh toán / hoàn tiền khi truy vấn bảng này.

Tôi đã cố gắng khai báo hai ánh xạ tham chiếu cả hai MoneyTransferMeanvới tên bảng và tên thực thể khác nhau tuy nhiên điều này dẫn tôi đến một ngoại lệ Duplicate class/entity mapping MoneyTransferMean+CashMoneyTransferMean.

Tôi cũng đã cố gắng sao chép ánh xạ lớp con nhưng tôi không thể chỉ định "ánh xạ cha" dẫn tôi đến ngoại lệ giống như trên.

Câu hỏi

Có một giải pháp tồn tại để duy trì các thực thể miền hiện tại của tôi?

Nếu không, công cụ tái cấu trúc nhỏ nhất tôi cần thực hiện trên các thực thể của mình để làm cho chúng bền bỉ với NHibnernate là gì?


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).: Tại sao không? Đó là thay đổi đơn giản và ngọt ngào sẽ giải quyết vấn đề của bạn. Bạn có thể tạo nên với ba giá trị có thể (mặc dù hai cũng sẽ làm gì với hồ sơ trùng lặp hoặc Flagloại): Payment, Refund, Both. Nếu hai giá trị làm cho bạn, booltài sản là tuyệt vời.
Amit Joshi

1
Tại sao bạn muốn lưu trữ các phương thức thanh toán đó trong cơ sở dữ liệu? Nhà nước ở đó là gì, ngoài cái tên?
berhalak

@AmitJoshi Mặc dù một thay đổi nhỏ như vậy có thể giải quyết vấn đề (bề ngoài), tôi muốn tránh thêm logic không liên quan đến kinh doanh vào miền của tôi.
Phát hiện

@berhalak Thật vậy, việc lưu trữ những thứ này trong cơ sở dữ liệu có vẻ hơi lộn xộn. Tuy nhiên đây là một yêu cầu từ dự án rằng tất cả các trạng thái phải có trong cơ sở dữ liệu.
Phát hiện

Câu trả lời:


0

Tại sao bạn không tạo một thực thể MoneyTransferMean , với tất cả các thuộc tính chung (các trường) và chỉ cần thêm 2 trường bổ sung (boolean) để xác định xem MoneyTransferMean là Thanh toán hay Hoàn tiền, hoặc cả hai ???? Kiên trì hay không.

Ngoài ra, nó có thể được thực hiện với một Thực thể bổ sung với Id (PK), thêm các trường bổ sung tương tự, mối quan hệ sẽ là 1: 1 với MoneyTransferMean. Xấu xí, tôi biết, nhưng nó nên hoạt động.


Tôi không muốn thêm sự phức tạp không liên quan đến tên miền vào dự án tên miền của tôi (chẳng hạn như thêm boolean mà sau đó nếu cần / khác là cần thiết). Ngoài ra, tôi không muốn những người sẽ sử dụng các lớp này mắc lỗi (bằng cách quên kiểm tra boolean và nghĩ rằng mỗi giá trị là một khoản hoàn trả có nghĩa là chẳng hạn). Đó là tất cả về nhân chứng.
Phát hiện

0

Tôi muốn thứ hai và thêm vào những gì @ DEVX75 đề xuất, trong đó các loại giao dịch của bạn về cơ bản mô tả cùng một khái niệm, mặc dù một loại là + ve trong khi loại kia là -ve. Có lẽ tôi chỉ cần thêm một trường boolean và có các hồ sơ riêng để phân biệt tiền hoàn trả từ các khoản thanh toán.

Giả sử bạn có UID và không sử dụng tên nhãn phương tiện làm ID, bạn có thể cho phép các tên trùng lặp cho phương tiện và bao gồm hai mục nhập tiền mặt, ví dụ:

UID, Nhãn, IsRefund

1, Tiền mặt, sai

2, Tiền mặt, đúng

3, Chứng từ, sai

4, Chứng từ, đúng

Sau đó, bạn có thể dễ dàng nhận được những điều sau đây:

Loại giao dịch = MoneyTransferMean.IsRefund? "Trả lại tiền thừa"

Giá trị giao dịch = MoneyTransferMean.IsRefund? MoneyTransfer.amount * -1: MoneyTransfer.amount

Bằng cách đó, nếu trong các giao dịch của bạn, bạn đã tham chiếu MoneyTransferMean.UID = 2, bạn biết rằng đó là khoản hoàn lại tiền mặt, thay vì biết rằng đó là loại giao dịch có thể là hoàn trả tiền mặt hoặc thanh toán bằng tiền mặt.


Ah bugger, chỉ cần lưu ý rằng bạn nói rằng bạn không muốn / không thể chỉnh sửa API công khai. Xin lỗi / bỏ qua câu trả lời của tôi, mặc dù tôi sẽ để lại vì có lẽ nó sẽ hữu ích cho những người khác có vấn đề / trường hợp sử dụng tương tự.
FrrifTPH

0

Cuối cùng, tôi quyết định giải quyết vấn đề bằng cách sao chép thực thể của mình MoneyTransferMeanthành hai thực thể PaymentMeanRefundMean.

Mặc dù tương tự trong triển khai, sự khác biệt giữa hai thực thể có ý nghĩa trong kinh doanh và đối với tôi là giải pháp tồi tệ nhất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.