views:

951

answers:

4

Hi,

I have a scenario in NHibernate where I have a one-to-many relationship between entities Employee and EmployeeStatus.

Employee has properties eg: ID, Name and an IList of EmployeeStatus, whilst EmployeeStatus, for the purposes of this question, just has it's own ID and some free text.

I don't need to hold a reference to Employee from EmployeeStatus, the management of status' will be done purely through the Employee entity - adding to the IList property. IE: I want to quite simply be able to do the following;

Employee e = new Employee();
e.Name = "Tony";
e.StatusList.Add( new EmployeeStatus("Status A") );
e.StatusList.Add( new EmployeeStatus("Status B") );
session.Save(e);

I've tried various methods, including creating a one way one-to-many mapping where inverse is false, cascade set to all-delete-orphan, which all looks like it should work, but it generates an exception about being unable to set the EmployeeId in EmployeeStatus. I'm led to believe that this is because NHibernate wants to do an insert with EmployeeId as NULL and then update it to the ID of the parent.

I guess I'm missing something here, so quite simply - can anyone tell me what my mapping file should look like to achieve the above?

Thanks in advance

Tony

-- edit: Heres a rough idea of the classes as requested --

public class Employee
{
  private IList<EmployeeStatus> _statusList;

  public Employee()
  {
    _statusList = new List<EmployeeStatus>();
  }

  public virtual int Id{ get; set; }

  public virtual string Name{ get; set; }

  public virtual IList<EmployeeStatus> StatusList
  {
    get
    {
      return _statusList;
    }
  }
}

public class EmployeeStatus
{
  public virtual int Id{ get; set; }
  public virtual string StatusText{ get; set; }

  public EmployeeStatus()
  {
  }

  public EmployeeStatus(string statusText)
  {
    StatusText = statusText;
  }
}
A: 

Can you post the code for the classes?

Are you trying to keep a history of statuses for an Employee?

-- Edit --
Looks like you are going to need many-to-many, since the child in the relationship (EmployeeStatus) has no reference back to the parent (Employee).

-- Edit 2 --
If you want the insert to be done as 1 call to the DB, you are going to need to add an Employee property to the EmployeeStatus class, and set the Inverse=true. And I'm pretty sure that you are going to need to add some logic which sets the bi-directional relationship in the objects. I.E.

public void AddStatus(EmployeeStatus status)
{
    this.StatusList.Add(status);
    status.Employee = this;
}
RKitson
It's part of a more complex domain model, but this is the only part i've been unable to get working, so I've simplified and condensed the whole thing down to the above. Thanks.
deepcode.co.uk
I may not of explained clearly there, but an employee status cannot be linked to more than one employee. It's definately 1 (employee) to many (status')....
deepcode.co.uk
RE: Edit 2 - yeah, this is what I figured, but I was hoping to avoid it as it pollutes my domain model with irrelevant information (Impossible to access status information without going through the employee itself). Thanks anyway.
deepcode.co.uk
A: 

I may not of explained clearly, but an employee status cannot be linked to more than one employee. It's definitely 1 (employee) to many (status')

In the physical database, the status entity has an employeeID field, which isn't in the domain - IE: I hold no reference back to employee from the status entity, but the physical field should be inferred from the owner of the collection - In fact, it does do this if I set the EmployeeID field in the status table to nullable - it actually executes 2 SQL statements - an insert and then an update, the EmployeeID being set in the update.

Thanks,

Tony

deepcode.co.uk
Can you post the .hbml files?
RKitson
A: 

Turns out that what I want to do isn't possible - you have to have a bi-directional association, and must set the child's parent reference. Not a massive problem I suppose, but didn't want to hold references in the child that I don't need within my code directly.

deepcode.co.uk
+1  A: 

The scenario you've described is just a basic one-to-many mapping. Here is the Fluent NHibernate mapping for this:

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        WithTable("Employee");
        HasMany(employee => employee.StatusList)
        .Cascade.All();
    }
}

You do not need to maintain a reference from EmployeeStatus back to Employee to achieve this.

Derek Greer