У меня есть таблица учетных записей, в которой хранятся основные и дополнительные учетные записи. Основные учетные записи в основном совпадают с дополнительными учетными записями, за исключением того, что они могут иметь связанную компанию. Account является абстрактным классом, и MasterAccount и SubAccount являются его производными.
MasterAccount - это любая запись учетной записи с нулевым ParentAccountId. Если запись учетной записи имеет ParentAccountId, то это SubAccount, а ParentAccountId ссылается на поле AccountId для MasterAccount.
Я пытаюсь получить сопоставления 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.
Любая помощь по правильному отображению этих отношений приветствуется.