2

I have a set of payment objects that come from different sources that I'd like to use an TPC inheritance in NHibernate for. The base for all these object is the payment processor (so all have a consistent format), however there is no representation of the base class in the database. I think I have my mapping worked out, except for the fact that I get an exception thrown when trying to insert - "Cannot use identity column key generation with <union-subclass> mapping for: <EntityName>"

Classes:

public class BasePayment
{
    public virtual int Id { get; set; }
    public virtual PaymentSource Source { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual decimal Amount { get; set; }
}

public class SubPayment : BasePayment
{
}

Mappings:

public class BasePaymentMap : ClassMap<BasePayment>
{
    public BasePaymentMap()
    {
        UseUnionSubclassForInheritanceMapping();
        DiscriminateSubClassesOnColumn("Source");
        Id(m => m.Id);
        Map(m => m.Source);
        Map(m => m.Amount);
        Map(m => m.Date);
    }
}

public class SubPaymentMap : SubclassMap<SubPayment>
{
    public SubPaymentMap()
    {
        DiscriminatorValue(PaymentSource.SourceX);
        Abstract();
        Table("SourceXPayments");
    }
}

And that's as far as I've got. On a SaveOrUpdate, I'm getting the error above, and a google search is not proving helpful thus far - I have found this question: Cannot use identity column key generation with <union-subclass> ( TABLE_PER_CLASS ) which appears to cover the issue in Java/Hibernate, but I'm having a problem with converting the @GeneratedValue(strategy = GenerationType.TABLE) into a Fluent syntax, as Fluent NHibernate's GeneratedBy() method doesn't seem to have a table, or a lot of documentation (that I have found) as to what it does under the covers.

Doing some more reading around it seems that this might not be possible, so if anyone can confirm this or offer a work around for the situation, it'd be greatly appreciated.

If I've not given enough detail, please let me know what would be more use.

Thanks in advance

Community
  • 1
  • 1
Ian Cotterill
  • 1,667
  • 4
  • 18
  • 28

1 Answers1

6
UseUnionSubclassForInheritanceMapping();
DiscriminateSubClassesOnColumn("Source");

is conflicting and FNH will ignore one.

UseUnionSubclassForInheritanceMapping means each class has it's own table with all columns and the table is used to discriminate the class, no column needed

DiscriminateSubClassesOnColumn means each class of the inheritance hierarchy live in the same table and a column is used to discriminate the classes.

the error message means that when using UseUnionSubclassForInheritanceMapping identity generation is not allowed since the id's would be unique for one table only but NHibernate threats all subclasses as one set where the id must be unique.

e.g. session.Get<BaseClass>(5); won't work relyably anymore since there could be more than one subclass with the same id.

@GeneratedValue(strategy = GenerationType.TABLE) just tells "use another strategy than identity". GeneratedBy.HiLow(); would be a good alternative to identity.

Firo
  • 30,626
  • 4
  • 55
  • 94
  • Thanks Firo - you've confirmed what I was reading after I posted. Though I understand why it won't let me do this, from my point of view it's an annoyance as it means I have to muddy either my tables or objects to make it fit. I'm looking at a different solution to it now, but thanks very much, this answers the original question. – Ian Cotterill May 28 '12 at 08:52
  • @Ian How did you end up solving this? I also don't want to create too much cruft in my classes. – Francois Botha Nov 07 '14 at 11:17
  • @FrancoisBotha the solution is to kick `DiscriminateSubClassesOnColumn("Source");` and use another Id-Generator. `GeneratedBy().HighLow(maxLowValue)` would be my recommendation where maxLowValue would be between 100 and 10000 – Firo Nov 07 '14 at 12:52
  • @FrancoisBotha Honestly can't remember - was working on something at my old job a long time ago. I know we didn't use an ID generator, but I can't look in the code to remind myself, sorry. Main solution for it was to stop using NHibernate in subsequent projects! – Ian Cotterill Nov 07 '14 at 13:50
  • @IanCotterill what were you using instead of NHibernate then? How does the new whatever solve this?= – Firo Nov 07 '14 at 15:33
  • @Firo sorry, I was being flippant - part of the issue was a lack of NH expertise, so moving to Dapper and handling the mapping/persistence ourselves worked a lot better as we were more in control. A lot of the issue we had with NH was how much it obfuscated and having a legacy DB that was enforcing a difficult domain model. The change to Dapper was also coupled with a shift in our domain model making everything a lot simpler for us. – Ian Cotterill Nov 07 '14 at 16:23
  • Thanks everyone. In the end I bit the bullet and went ahead with a HiLo approach as demonstrated in http://www.philliphaydon.com/2010/10/using-hilo-with-fluentnhibernate/ . I went with a row per table approach. – Francois Botha Nov 08 '14 at 10:30