I need to map a legacy table using Fluent NHibernate. I have no control over the table structure.
The table looks like this:
TypeId ObjectId Data
10 1 ... //Cat 1
10 2 ... //Cat 2
20 1 ... //Dog 1
30 1 ...
I am attempting to map this using a table-per-subclass structure using a discriminator value for TypeId
.
public abstract class Animal
{
public virtual int ObjectId { get; set; }
public virtual string Data { get; set; }
}
public class AnimalMap : ClassMap<Animal>
{
public AnimalMap()
{
Table("MyAnimals");
Id(x => x.ObjectId);
Map(x => x.Data);
DiscriminateSubClassesOnColumn("TypeId")
.AlwaysSelectWithValue();
}
}
public class Cat : Animal
{
}
public class CatMap : SubclassMap<Cat>
{
public CatMap()
{
DiscriminatorValue("10");
}
}
public class Dog : Animal
{
}
public class DogMap : SubclassMap<Dog>
{
public DogMap()
{
DiscriminatorValue("20");
}
}
The problem occurs when I try to load Cat 1
after Dog 1
, or vice versa.
var a = session.Get<Dog>(1); //Dog1
var b = session.Get<Cat>(1); //null
If I evict the first animal before fetching the second, it works.
var a = session.Get<Dog>(1); //Dog1
session.Evict(a);
var b = session.Get<Cat>(1); //Cat1
When I map both a Dog
and a Cat
to my AnimalHome
class, I get the following exception:
Unable to cast object of type 'MyNamespace.Dog' to type 'MyNamespace.Cat'.
This leads me to believe that the cache doesn't differentiate the Dog
and Cat
by their types. It just thinks of it as Animal 1
and that Cat 1
equals Dog 1
.
Can I somehow make the cache take the actual subclass into account? Alternatively, if this is not possible with a table-per-subclass structure, how should I approach mapping this table?
I solved this by ditching the Discriminator. A
Where
mapping was more appropriate in my case, as I don't actually need to treat theDog
orCat
as anAnimal
in my code. I still keep code duplication to a minimum by inheriting theAnimal
-related mappings.The cache now understands that a
Cat
is not aDog
.