Thanks for the thorough explanation. It was very helpful. I went on to
add one more discriminator (ClientUser) to the User mapping.

        <class name="User" table="Users" abstract ="false">
                <id name="Id" type="Int32" column="UserId">
                        <generator class="identity" />
                </id>
                <discriminator column="Type"/>
                <subclass name="Employee" discriminator-value="1">
                        <many-to-one name="Role" column ="RoleId" class 
="Role"/>
                </subclass>
                <subclass name="ClientUser" discriminator-value="2">
                        <many-to-one name="Client" column ="ClientId" class 
="Client"/>
                </subclass>

Then I started to realize that there is a database design problem.
Here is the User table (simplified).

UserId       Name       Type                         RoleId
ClientId
1       Mary    1 (employee)    1       NULL
2       John    1                       2       NULL
3              Steve         2 (client's user)         null
1

RoleId and ClientId are foreign keys. Based on the current design,
either foreign key will be null for all records. An employee has a
role but no client while a client's user has a client but no role. So,
I need some kinds of conditional foreign key. But it cannot be done in
the database according to my research on the Internet. I am wondering
whether I should split the User table into Employee table and
ClientUser table. Then I will have to change the NH inheritance
mapping. The only downside is that I will have to repeat all the
columns that the discriminator columns currently share. So, is there a
way to keep my current design? Or is splitting User table the better
way to go?

Thanks.

On Sep 3, 11:51 am, Anne Epstein <[email protected]> wrote:
> Looks like you have a problem where you identified your foreign key....
> <many-to-one name="Role" column ="*Id*" class ="Role"/>
> ....
> <bag name="Employees" cascade ="all-delete-orphan" inverse="true">
>                       <key column="*Id*"  />
>
> What you're telling Nhibernate is that the the column "ID" of your Users
> table is also the foreign key to the Roles table. so, when you attach a role
> to the user, it tries to update the role foreign key, which, again, is also
> your primary key of the Users table, and it's complaining about that.  What
> you want is probably something like:
>
> <many-to-one name="Role" column ="*RoleId*" class ="Role"/>
> ....
> <bag name="Employees" cascade ="all-delete-orphan" inverse="true">
>                       <key column="*RoleId*"  />
>
> Also, you probably want inverse = "true" on your Employees bag... bags work
> a bit more efficiently this way, and it will allow you to add a constraint
> to your db table (without inverse=true, NH will add the employees first with
> a null role, then go in afterward and add the role in).
>
>               <bag name="Employees" cascade ="all-delete-orphan" *
> inverse="true"*>
>                       <key column="RoleId"  />
>                       <one-to-many class="Employee" />
>               </bag>
> This will say the child is in control of propagating the relationship to the
> database
>
> Lastly, you don't show it, and you may have this already, but you'll want to
> make sure the bidirectional parent-child relationship is synched on both
> sides, thinks could get weird otherwise (this does not happen automatically
> to the objects in memory) so if you don't have them, you'll want to add
> methods that group both assignments together, perhaps something like this in
> Role:
>
> public virtual class AddEmployee(Employee employee){
>     Employees.Add(employee);
>     employee.Role = this;
>
> }
>
> public virtual class RemoveEmployee(Employee employee){
>     Employees.Remove(employee);
>     employee.Role = null;}
>
> (that won't delete the employee, only detach it from the role)
>
>
>
>
>
> On Thu, Sep 3, 2009 at 9:27 AM, Roger<[email protected]> wrote:
>
> > I have these domain models(simplified):
>
> >        public class Role : Entity
> >        {
> >                public Role() { }
>
> >                public virtual IList<Employee> Employees { get; protected
> set; }
> >        }
>
> >        public class Employee : User
> >        {
> >                public Employee() { Role = new Role(); }
>
> >                public virtual Role Role { get; protected set; }
> >        }
>
> >    public class User : Entity
> >    {
> >        public virtual UserType Type { get; set; }//UserType is an
> > emum. i.e. Employee = 1
> >    }
>
> > Here are the mappings. Employee is a discriminator.
>
> >        <class name="User" table="Users" abstract ="false">
> >                <id name="Id" type="Int32" column="Id">
> >                        <generator class="identity" />
> >                </id>
> >                <discriminator column="Type"/>
> >                <property name="Type"/>
> >                <subclass name="Employee" discriminator-value="1">
> >                        <many-to-one name="Role" column ="Id" class
> ="Role"/>
> >                </subclass>
>
> >        <class name="Role" table="Roles">
> >                <id name="Id" type="Int32" column="Id">
> >                        <generator class="identity" />
> >                </id>
>
> >                <bag name="Employees" cascade ="all-delete-orphan">
> >                        <key column="Id"  />
> >                        <one-to-many class="Employee" />
> >                </bag>
> >        </class>
>
> > When I called IRepository.SaveOrUpdate(employee), I kept getting an
> > error. The generated sql query was trying to update the primary key of
> > the User table. That's why it failed. The problem was solved when I
> > removed the column and class attributes of the many-to-one element:
>
> > <many-to-one name="Role" />
>
> > Does the column or the class attribute do anything special to table
> > per hierarchy mapping? Is that an expected behavior?
>
> > Thanks.- Hide quoted text -
>
> - Show quoted text -
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"nhusers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/nhusers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to