FluentNHibernate 子类和分层数据
我有一个存储主帐户和子帐户的帐户表。主账户与子账户基本相同,只是它们可以拥有关联公司。 Account 是一个抽象类,MasterAccount 和 SubAccount 都派生自它。
MasterAccount 是具有 null ParentAccountId 的任何帐户条目。如果帐户记录具有 ParentAccountId,则它是子帐户,并且 ParentAccountId 引用 MasterAccount 的 AccountId 字段。
我正在尝试为它们获取 FluentNhibernate 映射。
这些类如下所示
public class Account : EntityBase
{
public Account() { }
public virtual string AccountNumber { get; set; }
public virtual string AccountName { get; set; }
public virtual string ContactRole { get; set; }
public virtual bool EmailBillDataFile { get; set; }
public virtual bool EmailBill { get; set; }
public virtual bool PostBill { get; set; }
public virtual BillingMethod BillingMethod { get; set; }
public virtual BillingAddressType BillingAddressType { get; set; }
public virtual Contact Contact { get; set; }
public virtual bool IsInvoiceRoot { get; set; }
public virtual string Password { get; set; }
public virtual bool HasRequestedInvoicing { get; set; }
public virtual bool IsInternational { get; set; }
public virtual decimal AmountPaid { get; set; }
public virtual decimal PreviousBill { get; set; }
public virtual void MakePayment(decimal amount)
{
MakePayment(amount, null);
}
public virtual void MakePayment(decimal amount, string invoiceNumber)
{
AmountPaid += amount;
if (string.IsNullOrEmpty(invoiceNumber))
LogActivity(string.Format("Made payment of {0:c}", amount));
else {
LogActivity(string.Format("Made payment of {0:c} on Invoice '{1}'", amount, invoiceNumber));
}
}
public virtual Invoice CreateInvoice()
{
Invoice invoice;
invoice = IsInternational ? new NoGstInvoice() : new Invoice();
// Can update invoice properties that rely on account data here.
return invoice;
}
#region Business Rules
public override IEnumerable<RuleViolation> GetRuleViolations()
{
if (string.IsNullOrEmpty(AccountName))
yield return new RuleViolation("Account Name required", "AccountName");
if (string.IsNullOrEmpty(AccountNumber))
yield return new RuleViolation("Acocunt Number required", "AccountNumber");
if (string.IsNullOrEmpty(Password))
yield return new RuleViolation("Password required", "Password");
yield break;
}
#endregion
}
public class MasterAccount : Account
{
private Company _company;
private IList<SubAccount> _subAccounts;
public MasterAccount() : this(null) { }
public MasterAccount(Company company)
{
_company = company;
_subAccounts = new List<SubAccount>();
}
public virtual Company Company
{
get { return _company; }
}
public virtual IEnumerable<SubAccount> SubAccounts
{
get { return _subAccounts; }
}
public virtual SubAccount CreateSubAccount(string accountNumber, string accountName)
{
var subAccount = new SubAccount(this)
{
AccountName = accountName,
AccountNumber = accountNumber,
Contact = this.Contact,
ContactRole = this.ContactRole,
PreviousBill = 0,
AmountPaid = 0,
BillingAddressType = this.BillingAddressType,
BillingMethod = this.BillingMethod,
IsInternational = this.IsInternational,
IsInvoiceRoot = false,
EmailBill = this.EmailBill,
EmailBillDataFile = this.EmailBillDataFile,
Password = this.Password,
PostBill = this.PostBill
};
return subAccount;
}
}
public class SubAccount : Account
{
private MasterAccount _masterAccount;
public SubAccount() { }
public SubAccount(MasterAccount master)
{
_masterAccount = master;
}
public virtual MasterAccount MasterAccount
{
get { return _masterAccount; }
}
}
我所拥有的映射是:
public class AccountMap : ClassMap<Account>
{
public AccountMap()
{
Table("Account");
Id(x => x.Id).Column("AccountId").GeneratedBy.Identity();
Map(x => x.AccountName).Length(50).Not.Nullable();
Map(x => x.AccountNumber).Length(10).Not.Nullable();
Map(x => x.ContactRole).Length(50);
Map(x => x.BillingMethod).Not.Nullable();
Map(x => x.EmailBill).Not.Nullable();
Map(x => x.PostBill).Not.Nullable();
Map(x => x.EmailBillDataFile).Not.Nullable();
Map(x => x.BillingAddressType).Not.Nullable();
Map(x => x.IsInvoiceRoot).Not.Nullable();
Map(x => x.HasRequestedInvoicing).Not.Nullable();
Map(x => x.IsInternational).Not.Nullable();
Map(x => x.PreviousBill).Not.Nullable();
Map(x => x.AmountPaid).Not.Nullable();
Map(x => x.Password).Length(20).Not.Nullable();
References(x => x.Contact).Column("ContactId").Not.Nullable();
DiscriminateSubClassesOnColumn("ParentAccountId");
}
}
public class MasterAccountMap : SubclassMap<MasterAccount>
{
public MasterAccountMap()
{
References(x => x.Company).Column("CompanyId");
HasMany(x => x.SubAccounts).KeyColumn("ParentAccountId").Inverse().Cascade.All();
}
}
public class SubAccountMap : SubclassMap<SubAccount>
{
public SubAccountMap()
{
References(x => x.MasterAccount).Column("ParentAccountId").Not.Nullable();
}
}
但是,当我执行以下测试时:
[Test]
public void Can_add_subAccount_to_database()
{
var master = Session.Get<MasterAccount>(1);
var subAccount = master.CreateSubAccount("TST123", "Test Account");
Session.Save(subAccount);
Session.Flush();
Session.Clear();
var fromDb = Session.Get<SubAccount>(subAccount.Id);
Assert.AreNotSame(subAccount, fromDb);
}
我在 Session.Save(subAccount); 上遇到异常。线。
System.ArgumentOutOfRangeException : Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
如果我注释掉 SubAccountMap 中的引用映射,则不会出现异常。
对于正确映射这种关系的任何帮助,我们表示赞赏。
I have an Account table that stores Master Accounts and Sub Accounts. Master Accounts are basically the same as Sub Accounts except that they can have an associated Company. Account is an abstract class and both MasterAccount and SubAccount derive from it.
A MasterAccount is any account entry with a null ParentAccountId. If an Account record has a ParentAccountId then it is a SubAccount and the ParentAccountId references the AccountId field for the MasterAccount.
I am trying get FluentNhibernate mappings for them.
The classes look like the following
public class Account : EntityBase
{
public Account() { }
public virtual string AccountNumber { get; set; }
public virtual string AccountName { get; set; }
public virtual string ContactRole { get; set; }
public virtual bool EmailBillDataFile { get; set; }
public virtual bool EmailBill { get; set; }
public virtual bool PostBill { get; set; }
public virtual BillingMethod BillingMethod { get; set; }
public virtual BillingAddressType BillingAddressType { get; set; }
public virtual Contact Contact { get; set; }
public virtual bool IsInvoiceRoot { get; set; }
public virtual string Password { get; set; }
public virtual bool HasRequestedInvoicing { get; set; }
public virtual bool IsInternational { get; set; }
public virtual decimal AmountPaid { get; set; }
public virtual decimal PreviousBill { get; set; }
public virtual void MakePayment(decimal amount)
{
MakePayment(amount, null);
}
public virtual void MakePayment(decimal amount, string invoiceNumber)
{
AmountPaid += amount;
if (string.IsNullOrEmpty(invoiceNumber))
LogActivity(string.Format("Made payment of {0:c}", amount));
else {
LogActivity(string.Format("Made payment of {0:c} on Invoice '{1}'", amount, invoiceNumber));
}
}
public virtual Invoice CreateInvoice()
{
Invoice invoice;
invoice = IsInternational ? new NoGstInvoice() : new Invoice();
// Can update invoice properties that rely on account data here.
return invoice;
}
#region Business Rules
public override IEnumerable<RuleViolation> GetRuleViolations()
{
if (string.IsNullOrEmpty(AccountName))
yield return new RuleViolation("Account Name required", "AccountName");
if (string.IsNullOrEmpty(AccountNumber))
yield return new RuleViolation("Acocunt Number required", "AccountNumber");
if (string.IsNullOrEmpty(Password))
yield return new RuleViolation("Password required", "Password");
yield break;
}
#endregion
}
public class MasterAccount : Account
{
private Company _company;
private IList<SubAccount> _subAccounts;
public MasterAccount() : this(null) { }
public MasterAccount(Company company)
{
_company = company;
_subAccounts = new List<SubAccount>();
}
public virtual Company Company
{
get { return _company; }
}
public virtual IEnumerable<SubAccount> SubAccounts
{
get { return _subAccounts; }
}
public virtual SubAccount CreateSubAccount(string accountNumber, string accountName)
{
var subAccount = new SubAccount(this)
{
AccountName = accountName,
AccountNumber = accountNumber,
Contact = this.Contact,
ContactRole = this.ContactRole,
PreviousBill = 0,
AmountPaid = 0,
BillingAddressType = this.BillingAddressType,
BillingMethod = this.BillingMethod,
IsInternational = this.IsInternational,
IsInvoiceRoot = false,
EmailBill = this.EmailBill,
EmailBillDataFile = this.EmailBillDataFile,
Password = this.Password,
PostBill = this.PostBill
};
return subAccount;
}
}
public class SubAccount : Account
{
private MasterAccount _masterAccount;
public SubAccount() { }
public SubAccount(MasterAccount master)
{
_masterAccount = master;
}
public virtual MasterAccount MasterAccount
{
get { return _masterAccount; }
}
}
The mappings I have are:
public class AccountMap : ClassMap<Account>
{
public AccountMap()
{
Table("Account");
Id(x => x.Id).Column("AccountId").GeneratedBy.Identity();
Map(x => x.AccountName).Length(50).Not.Nullable();
Map(x => x.AccountNumber).Length(10).Not.Nullable();
Map(x => x.ContactRole).Length(50);
Map(x => x.BillingMethod).Not.Nullable();
Map(x => x.EmailBill).Not.Nullable();
Map(x => x.PostBill).Not.Nullable();
Map(x => x.EmailBillDataFile).Not.Nullable();
Map(x => x.BillingAddressType).Not.Nullable();
Map(x => x.IsInvoiceRoot).Not.Nullable();
Map(x => x.HasRequestedInvoicing).Not.Nullable();
Map(x => x.IsInternational).Not.Nullable();
Map(x => x.PreviousBill).Not.Nullable();
Map(x => x.AmountPaid).Not.Nullable();
Map(x => x.Password).Length(20).Not.Nullable();
References(x => x.Contact).Column("ContactId").Not.Nullable();
DiscriminateSubClassesOnColumn("ParentAccountId");
}
}
public class MasterAccountMap : SubclassMap<MasterAccount>
{
public MasterAccountMap()
{
References(x => x.Company).Column("CompanyId");
HasMany(x => x.SubAccounts).KeyColumn("ParentAccountId").Inverse().Cascade.All();
}
}
public class SubAccountMap : SubclassMap<SubAccount>
{
public SubAccountMap()
{
References(x => x.MasterAccount).Column("ParentAccountId").Not.Nullable();
}
}
However, when I execute the following test:
[Test]
public void Can_add_subAccount_to_database()
{
var master = Session.Get<MasterAccount>(1);
var subAccount = master.CreateSubAccount("TST123", "Test Account");
Session.Save(subAccount);
Session.Flush();
Session.Clear();
var fromDb = Session.Get<SubAccount>(subAccount.Id);
Assert.AreNotSame(subAccount, fromDb);
}
I get an exception on the Session.Save(subAccount); line.
System.ArgumentOutOfRangeException : Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
I do not get the exception if I comment out the References mapping in SubAccountMap.
Any help on correctly mapping this relationship is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
似乎我需要使用 DiscrimminateSubClassesOnColumn 的 Formula 方法
,然后在每个子类中使用以下内容,
请参阅 http://wiki。 Fluentnhibernate.org/Fluent_mapping
Seems I needed to use the Formula method off DiscriminateSubClassesOnColumn
and then use the following in each of the subclasses
see http://wiki.fluentnhibernate.org/Fluent_mapping