在关系数据库的 table 上,哪一个应该是首选 1:1,0 或可为空的字段?
Which one should be preferred 1:1,0 or nullable fields on one table on relational database?
我首先使用 Azure Sql 和实体框架代码。
我有Transaction
Table。有buy/sell
、withdrawal
、deposit
、fee
、
4种类型
例如,我需要 DepositCode
进行存款交易,但对于其他人,此列将为空。我还需要 ItemPrice
和 ItemAmount
用于 buy/sell 但对于其他类型它将为空。
例子Transaction
Table
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);
}
应该首选哪一个?
如果可能,我更喜欢可为空的字段,这是 table 每个 class 层次结构 映射中的实现。使用这种方法,EF 会将所有事务对象存储在一个 table 中,并将使用鉴别器列来为您管理类型加载。那就是说我会按如下方式重构您的模型:
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; }
}
您实际上只有三笔交易:buy/sell、deposit/withdrawal、手续费。买入和卖出的区别在于金额为正为买入,金额为负为卖出。存款和取款也是如此。
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 )
);
其他 tables(或子tables,如果你想这样想的话)看起来像这样:
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 )
);
至于代码,最好的方法可能是有一个抽象的超级 class 交易,其中包含 subclasses BuySell、DepositWithdrawal 和 Fee。我还会提供一些方便的视图,巧合的是,BuySell、DepositWithdrawal 和 Fee。这些视图将提供交易 table 与适当子 table 的联合数据集。视图上的触发器(您的系统允许)将大大简化应用程序代码,因为每个 subclass 将仅通过视图进行查询和操作。代码甚至不需要知道数据库中的物理布局。
我首先使用 Azure Sql 和实体框架代码。
我有Transaction
Table。有buy/sell
、withdrawal
、deposit
、fee
、
例如,我需要 DepositCode
进行存款交易,但对于其他人,此列将为空。我还需要 ItemPrice
和 ItemAmount
用于 buy/sell 但对于其他类型它将为空。
例子Transaction
Table
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);
}
应该首选哪一个?
如果可能,我更喜欢可为空的字段,这是 table 每个 class 层次结构 映射中的实现。使用这种方法,EF 会将所有事务对象存储在一个 table 中,并将使用鉴别器列来为您管理类型加载。那就是说我会按如下方式重构您的模型:
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; }
}
您实际上只有三笔交易:buy/sell、deposit/withdrawal、手续费。买入和卖出的区别在于金额为正为买入,金额为负为卖出。存款和取款也是如此。
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 )
);
其他 tables(或子tables,如果你想这样想的话)看起来像这样:
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 )
);
至于代码,最好的方法可能是有一个抽象的超级 class 交易,其中包含 subclasses BuySell、DepositWithdrawal 和 Fee。我还会提供一些方便的视图,巧合的是,BuySell、DepositWithdrawal 和 Fee。这些视图将提供交易 table 与适当子 table 的联合数据集。视图上的触发器(您的系统允许)将大大简化应用程序代码,因为每个 subclass 将仅通过视图进行查询和操作。代码甚至不需要知道数据库中的物理布局。