在关系数据库的一个表上哪一个应该首选1:1,0或可空字段?

时间:2015-05-08 11:08:28

标签: entity-framework database-design orm ef-code-first relational-database

我使用Azure Sql和Entity-Framework Code First。

我有Transaction表。共有4种类型buy/sellwithdrawaldepositfee

例如,我需要DepositCode存款交易,但此列对其他人而言为空。此外,我需要ItemPriceItemAmount进行买入/卖出,但对于其他类型,它将为空。

示例Transaction

 public class Transaction
    {
        public long Id { get; set; }
        public decimal Amount { get; set; }
        public int Type { get; set; }
        public string DepositCode { get; set; }
        public decimal? ItemPrice { get; set; }
        public decimal? ItemAmount { get; set; }
        public string WithdrawalIban { get; set; }
    }

 public class Transaction
    {
        public long Id { get; set; }
        public decimal Amount { get; set; }
        public int Type { get; set; }
        public DepositTransaction DepositTransaction { get; set; }
        public WithdrawalTransaction BuyAndSellTransaction { get; set; }
        public WithdrawalTransaction WithdrawalTransaction { get;set; }
    }


 public class DepositTransaction
    {
        public long Id { get; set; }
        public Transaction Transaction { get; set; }
        public string DepositCode { get; set; }
    }


 public class WithdrawalTransaction
    {
        public long Id { get; set; }
        public Transaction Transaction { get; set; }
        public string WithdrawalIban { get; set; }
    }


 public class BuySellTransaction
    {
        public long Id { get; set; }
        public Transaction Transaction { get; set; }
        public decimal ItemPrice { get; set; }
        public decimal ItemAmount { get; set; }
    }

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<WithdrawalTransaction>()
        .HasRequired(wt => wt.Transaction)
        .WithOptional(tr => tr.WithdrawalTransaction);

        modelBuilder.Entity<DepositTransaction>()
      .HasRequired(db => db.Transaction)
      .WithOptional(tr=> tr.DepositTransaction);

        modelBuilder.Entity<BuySellTransaction>()
      .HasRequired(bs => bs.Transaction)
      .WithOptional(tr => tr.BuySellTransaction);

    }

哪一个应该首选?

2 个答案:

答案 0 :(得分:1)

我尽可能使用可空字段,这是表中每个类层次结构映射的实现。使用这种方法,EF会将所有事务对象存储在一个表中,并使用一个鉴别器列来管理类型加载。那说我会按如下方式重构你的模型:

public abstract class Transaction
{
    public long Id { get; set; }
    public DateTime TransactionDate { get; set; }
}


public class DepositTransaction : Transaction
{
    public string DepositCode { get; set; }
}


public class WithdrawalTransaction : Transaction
{
    public string WithdrawalIban { get; set; }
}


public class BuySellTransaction : Transaction
{
    public decimal ItemPrice { get; set; }
    public decimal ItemAmount { get; set; }
}

答案 1 :(得分:1)

您实际上只有三笔交易:买入/卖出,存款/取款,费用。买入和卖出之间的区别在于买入为正,卖出为负。存款和取款也是如此。

create table Transactions(
    ID         bigint identity primary key,
    XType      char( 1 ) not null, -- 'B': buy/sell, 'D': dep/with, 'F': fee
    Amount     money not null,
    constraint CK_Transaction_Type check( XType in( 'B', 'D', 'F' ),
    constraint UQ_Transaction_Type unique( ID, XType )
);

其他表(或子表如果你想将它们视为这样)将如下所示:

create table BuySellTrans(
    TransID    bigint not null,
    TransType  char( 1 ) not null,
    ...,   -- other info regarding purchase or sale
    constraint CK_BuySellTrans_BuySellType check( TransType = 'B' )
    constraint FK_BuySellTrans_Trans foreign key( TransID, TransType )
        references Transactions( ID, XType )
);

至于代码,最好的方法可能是拥有子类BuySell,DepositWithdrawal和Fee的抽象超类Transaction。我还会提供一些方便的视图,巧合的是,BuySell,DepositWithdrawal和Fee。这些视图将提供Transactions表的连接数据集以及相应的子表。视图上的触发器(允许您的系统)将大大简化应用程序代码,因为每个子类只能通过视图进行查询和操作。代码甚至不需要知道数据库中的物理布局。