FluentNHibernate 子类和分层数据

发布于 2024-11-14 18:42:04 字数 7153 浏览 1 评论 0原文

我有一个存储主帐户和子帐户的帐户表。主账户与子账户基本相同,只是它们可以拥有关联公司。 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花海 2024-11-21 18:42:04

似乎我需要使用 DiscrimminateSubClassesOnColumn 的 Formula 方法

DiscriminateSubClassesOnColumn("").Formula("case when parentaccountid is null then '0' else '1' end");

,然后在每个子类中使用以下内容,

DiscriminatorValue("0");  // In MasterAccountMap

DiscriminatorValue("1"); // in SubAccountMap

请参阅 http://wiki。 Fluentnhibernate.org/Fluent_mapping

Seems I needed to use the Formula method off DiscriminateSubClassesOnColumn

DiscriminateSubClassesOnColumn("").Formula("case when parentaccountid is null then '0' else '1' end");

and then use the following in each of the subclasses

DiscriminatorValue("0");  // In MasterAccountMap

DiscriminatorValue("1"); // in SubAccountMap

see http://wiki.fluentnhibernate.org/Fluent_mapping

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文