Cannot instantiate abstract class or interface exception

1,825 views
Skip to first unread message

Rohit

unread,
May 4, 2009, 7:36:23 PM5/4/09
to nhusers
Hi,

I am using NHibernate version 2.0.1.

I have an User class which has a collection of 'Role'. Role is an
abstract class from which 2 concrete classes derive - 'Mentor' and
'Teacher'.

_______ ___________
| | | |
| User | ------------------>| Role |
|______| | __________|
^
|
________ |__________________
_______ |___ _________ |__________
| |
| |
| Mentor | |
Teacher |
|___________| |____________________|

The User mapping is as follows:

<class name="User" table="User">
<id name="Id" column="UserID">
<generator class="native" />
</id>
<set name="Roles">
<key column="UserID" />
<one-to-many class="Role" />
</set>
</class>

And the Role mapping is as:

<class name="Role" table="UserRoles">
<composite-id>
<key-many-to-one name="AssignedTo" class="User" column="UserID" /
>
<key-many-to-one name="Type" class="RoleType" column="RoleID" />
</composite-id>

<discriminator column="RoleID" insert="false" />

<subclass name="Mentor" discriminator-value="1" />
<subclass name="Teacher" discriminator-value="2" />
</class>

As we can see, Role has a composite id, which is a mapping to the User
class and a RoleType class.

When I try to retrieve a role for a user, I am getting the following
error:
NHibernate.InstantiationException : Cannot instantiate abstract class
or interface:Role

The subclass has always worked for me with other objects. Only here,
when using a composite-id, I am getting this error.

Can somebody help me please? This is the first time I am posting on
this forum. So if there is any additional information I can provide,
please let me know.

Many Thanks,
Rohit


Anne Epstein

unread,
May 4, 2009, 11:55:31 PM5/4/09
to nhu...@googlegroups.com
Hi Rohit, welcome to the group! Looking at your issue, the error
message is about an abstract class, so my guess you're having problems
because it's trying to work with Roles directly.

Thinking about this a little more, here's a thought: what will happen
if you have some bad data in your discriminator column-say, null, or
something other than 1 or 2. It'll try to create a concrete Role class
instead of your subclasses. That would certainly generate your error,
or something very similar.

Alternatively, you may have better luck if you instead used an
interface, as illustrated here:
http://www.nhforge.org/doc/nh/en/index.html#inheritance-tableperclass
if you're still having problems, it's worth a try...even if the
classes inherit from a class behind the scenes, I think it's safer to
work with an interface they share.

Rohit

unread,
May 5, 2009, 2:22:03 PM5/5/09
to nhusers
Thanks Anne for your response.

1) There is no bad data in the discriminator column. I am running this
over a test database, and I have only 1 row in the UserRoles table.

2) I tried with an interface. But same error. I don't think its the
abstract class causing this issue. The error message says -
"Cannot instantiate abstract class or interface".

Could it be the composite id?

<composite-id>
<key-many-to-one name="AssignedTo" class="User" column="UserID" />
<key-many-to-one name="Type" class="RoleType" column="RoleID" />
</composite-id>

Thanks,
Rohit

On May 4, 8:55 pm, Anne Epstein <aje...@gmail.com> wrote:
> Hi Rohit, welcome to the group! Looking at your issue, the error
> message is about an abstract class, so my guess you're having problems
> because it's trying to work with Roles directly.
>
> Thinking about this a little more, here's a thought: what will happen
> if you have some bad data in your discriminator column-say, null, or
> something other than 1 or 2. It'll try to create a concrete Role class
> instead of your subclasses. That would certainly generate your error,
> or something very similar.
>
> Alternatively, you may have better luck if you instead used an
> interface, as illustrated here:http://www.nhforge.org/doc/nh/en/index.html#inheritance-tableperclass
> if you're still having problems, it's worth a try...even if the
> classes inherit from a class behind the scenes, I think it's safer to
> work with an interface they share.
>

Anne Epstein

unread,
May 5, 2009, 3:06:55 PM5/5/09
to nhu...@googlegroups.com
Hi Rohit,
I still don't think it's likely to be the composite ID:

I ran a quick search on that message in the NHibernate codebase, and
the one place that error is generated is in PocoInstantiator.cs:
public object Instantiate()
{
if (ReflectHelper.IsAbstractClass(mappedClass))
{
throw new InstantiationException("Cannot instantiate abstract
class or interface: ", mappedClass);
}
.... <more code here>


The IsAbstractClass method in ReflectorHelper is simply this:
public static bool IsAbstractClass(System.Type type)
{
return (type.IsAbstract || type.IsInterface);
}


It's pretty straightforward- it *really* looks like if you're getting
that error, it's because it's trying to instantiate an abstract
class/interface. My best guess is still a discriminator problem,
maybe even something less-obvious like your id col is a string and
it's got a space in it.

If you don't have log4net logging turned on yet, you might give that a
go-the sql you're generating might give you some ideas.

Good luck!

Jason Meckley

unread,
May 5, 2009, 3:35:30 PM5/5/09
to nhusers
isn't there an attribute you apply to the Role class mapping to let NH
know Role is abstract?

On May 5, 3:06 pm, Anne Epstein <aje...@gmail.com> wrote:
> Hi Rohit,
> I still don't think it's likely to be the composite ID:
>
> I ran a quick search on that message in the NHibernate codebase, and
> the one place that error is generated is in PocoInstantiator.cs:
>                 public object Instantiate()
>                 {
>                         if (ReflectHelper.IsAbstractClass(mappedClass))
>                         {
>                                 throw new InstantiationException("Cannot instantiate abstract
> class or interface: ", mappedClass);
>                         }
> .... <more code here>
>
> The IsAbstractClass method in ReflectorHelper is simply this:
>                 public static bool IsAbstractClass(System.Type type)
>                 {
>                         return (type.IsAbstract || type.IsInterface);
>                 }
>
> It's pretty straightforward- it *really* looks like if you're getting
> that error, it's because it's trying to instantiate an abstract
> class/interface.  My best guess is still a discriminator problem,
> maybe even something less-obvious like your id col is a string and
> it's got a space in it.
>
> If you don't have log4net logging turned on yet, you might give that a
> go-the sql you're generating might give you some ideas.
>
> Good luck!
>

Rohit

unread,
May 5, 2009, 4:22:09 PM5/5/09
to nhusers
Thanks to Anne and Jason for your help. I have tried a few more things
-

1) To test that if this really was a discriminator problem, I tried to
reproduce this error with another hierarchy in my application. I
changed the discriminator column to point to a column which I knew had
bad data. The error I got in that case was:

NHibernate.WrongClassException : Object with id: 41 was not of
the specified subclass: ProductType (Discriminator was: '1')

So, this shows that if NHibernate cannot match the discriminator to an
existing discriminator value, then will throw this error.

2) I ran the log4net logging, and it generated the sql query
perfectly, and binded the correct return values to the correct
columns. Here's the sql query -

SELECT this_.UserID as UserID15_0_,
this_.RoleID as RoleID15_0_
FROM UserRoles this_
WHERE this_.UserID = 979488

I saw that the RoleID (which is the discriminator) came back as '1',
which is correct.

3) I also tried applying the abstract attribute to the Role class.

<class name="Role" table="UserRoles" abstract="true">

This did not help, and I get the same error.

I have tried so many things, read the documentation, searched forums.
But I am ready to try more suggestions that anyone can suggest.

Again, thanks everybody.
- Rohit

Rohit

unread,
May 5, 2009, 5:02:19 PM5/5/09
to nhusers
I think I have proved that this is a composite id issue.

I changed the 'Role' code above from:

<class name="Role" table="UserRoles">
<composite-id>
<key-many-to-one name="AssignedTo" class="User" column="UserID" />
<key-many-to-one name="Type" class="RoleType" column="RoleID" />
</composite-id>
<discriminator column="RoleID" insert="false" />
<subclass name="Mentor" discriminator-value="1" />
<subclass name="Teacher" discriminator-value="2" />
</class>

To:

<class name="Role" table="UserRoles">
<id name="Id" column="RoleID">
<generator class="native" />
</id>
<discriminator column="RoleID" insert="false" />
<many-to-one name="AssignedTo" class="User" column="UserID" />
<subclass name="Mentor" discriminator-value="1" />
<subclass name="Teacher" discriminator-value="2" />
</class>

Although this is a wrong mapping for my domain, but this worked
beautifully. The subclass was created using discriminator column.

Does anyone has any idea why the Table-per-class hierarchy does not
work with composite-id Classes?

Thanks,
Rohit

Rohit

unread,
May 5, 2009, 8:03:40 PM5/5/09
to nhusers
After doing more trial-and-errors I think I have found a solution.

Table-per-class works with Composite-id, but only if the composite is
implemented as a class. In my example, I created a RoleCompositeId
class:

public class RoleCompositeId
{
public virtual int UserId { get; set; }
public virtual int RoleId { get; set; }
}

And my mapping files looks like this:

<class name="Role" table="UserRoles">
<composite-id name="Id" class="RoleCompositeId">
<key-property name="UserId" column="UserID" />
<key-property name="RoleId" column="RoleID" />
</composite-id>
<discriminator column="RoleID" insert="false" />
<many-to-one name="AssignedTo" class="User" column="UserID" />
<many-to-one name="Type" class="RoleType" column="RoleID" />
<subclass name="Mentor" discriminator-value="1" />
<subclass name="Teacher" discriminator-value="2" />
</class>

And this worked!

Thanks,
Rohit
Reply all
Reply to author
Forward
0 new messages