4
votes

Essentially the title of this question explains the essense of what I am trying to do, but to create a contrived example...

I have a class, call it Employee. Employee has an IPaymentBehaviour...

public class Employee 
{
  IPaymentBehaviour _paymentBehaviour;

  protected internal Employee() { /* required by NH */}

  public Employee(IPaymentBehaviour paymentBehaviour)
  {
    _paymentBehaviour = paymentBehaviour;
  }

}

This corresponds to a database table like so:

dbo.Employees
-> EmployeeId (primary key)
-> PaymentBehaviourId (foreign key to lookup table)
-> Field1
-> Field2
-> Field3
-> Field4

Depending on the value of PaymentBehaviourId I need to 'inject' a different implementation of IPaymentBehaviour into the Employee object. Depending on which PaymentBehaviour was in use, Field1, 2, 3 or 4 might be needed to create that behaviour.

Can anyone tell me how this would be mapped using Fluent-NHibernate?

3
What do you mean with "Field1, 2, 3 or 4 might be needed to create that behaviour"? What do you mean with "create"? Is it possible to change the database design? - Stefan Steinegger
I mean that those are the names in the table, and depending on which behaviour is required you would use those fields to create the instance of that behaviour. It is possible to change the db design, yes, but we have many possible combinations so it needs to be as generic as possible. - KevinT

3 Answers

2
votes

table Employees

  • EmployeeId (primary key)
  • PaymentBehaviourId (foreign key to PaymentBehaviour)

table PaymentBehaviour

  • PaymentBehaviourId (pk)
  • type (discriminator)
  • Field1
  • Field2
  • Field3
  • Field4

Classes

public class Employee 
{
  /* ... */  
  public PaymentBehaviour PaymentBehaviour { get; set; }
}

public class PaymentBehaviourA : IPaymentBehaviour
{
  /* ... */  
  public int Field1 { get; set; }
}

public class PaymentBehaviourB : IPaymentBehaviour
{
  /* ... */  
  public int Field2 { get; set; }
}

I don't know FluentNHibernate enough to tell you how it looks like, but in XML you would specify it like this:

<class name="Employee" table="Employees">
  <many-to-one name="PaymentBehaviour" class="IPaymentBehaviour">
</class>

<class name="IPaymentBehaviour" abstract="true" >
  <discriminator column="type"/>

  <subclass name="PaymentBehaviourA" discriminator-value="A">
    <propert name="Field1"/>
  </subclass>

  <subclass name="PaymentBehaviourB" discriminator-value="B">
    <propert name="Field2"/>
  </subclass>
</class>
1
votes

NHibernate uses the default constructor to instantiate entities. There are some workarounds though.

0
votes

I think I would work around it like this:

  • Create a default constructur on the Employee object , that has a private access modifier, so that NHibernate can reconstruct those types
  • Create an Interceptor in where you overload the appropriate methods (OnLoad I presume), in which you make sure that you inject the correct IPaymentBehaviour implementation into the entity. (Perhaps you can create an interface 'IPaymentBehaviourInjectable' that can be implemented by the Employee class (implement it explicitily), so that you can inject the correct behaviour into the entity ...