How to map inheritance with property returned other inheritance? - nhibernate

I have abstract class Vehicle and two classes that derive from: Car and ForkLift.
public abstract class Vehicle
{
public EngineBase Engine { get; set; }
}
public class Car : Vehicle
{
public GasEngine Engine { get; set; }
}
public class ForkLift : Vehicle
{
public ElectricEngine Engine { get; set; }
}
and Engine clasess:
public abstract class EngineBase
{
}
public class GasEngine : EngineBase
{
}
public class ElectricEngine : EngineBase
{
}
Engines are mapped with "table per class hierarchy". With Vehicles I want to use the same pattern.
How to map Engine class and derived with that Engine property?
How to do it with lazy-loading?

That code does not compile, which makes it improbable that you can map it.

Use a protected field in Vehicle and map it with an access strategy:
public abstract class Vehicle
{
protected Engine _engine;
}
In Fluent NHibernate this would be mapped:
References(x => x.Engine, "EngineId").Access.CamelCaseField(Prefix.Underscore);
Then the classes that extend Vehicle can cast it as needed:
public class Car : Vehicle
{
public GasEngine
{
get { return (GasEngine)_engine; }
set { _engine = Value; }
}
}

Related

Fluent Nhiberante sub class same table as class

I have two classes:
class User {
public int Id { get;set; }
public string Name { get; set; }
}
class VerifiedUser : User {
public ICollection<Verified> { get; set; }
}
I would like NHibernate to treat VerifiedUser and User as the same table but keep them separate to, so.
Session.Query<User>() //would return a User
Session.Query<VerifiedUser>() //would return a VerifiedUser
Is this possible or is it unsupported?
You will need to implement the table-per-hierarchy strategy with Fluent Nhiberate in mapping classes. These are like overrides for the AutoMapping feature (if used) of FNH, otherwise mapping classes are de facto and you will be used to them.
Something like:
public class UserMappingOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.DiscriminateSubClassesOnColumn("IsVerified").Not.Nullable();
}
}
public class VerifiedUserClassMap : SubclassMap<VerfiedUser>
{
public VerifiedUserClassMap()
{
DiscriminatorValue("Yes");
}
}
And to answer your question, yes as far as I remember nothing to do here: Session.QueryOver<VerifiedUser>() as NHibernate will add on the where clause for the discriminator

NHibernate 3.3.1 explicit polymorphism

I use NH 3.3.1.
Suppose simple classes:
public class TestBase
{
public virtual int Id { get; set; }
public virtual string A { get; set; }
}
public class Test : TestBase
{
public virtual string B { get; set; }
}
and mappings for them:
public sealed class TestBaseMap : ClassMap<TestBase>
{
public TestBaseMap()
{
this.Polymorphism.Explicit();
this.Id(a => a.Id).GeneratedBy.Identity();
this.Map(a => a.A);
}
}
public sealed class TestMap :SubclassMap<Test>
{
public TestMap()
{
this.Map(a => a.B);
}
}
Even with Polymorphism.Explicit() specified, NH still left joins Test when querying for TestBase.
var a = this.Session.Get<TestBase>(1);
I don't really need this joining 'cuz will have lots of subclasses.
I checked xml generated by fluent. it's ok, "explicit" clause is there. What am i doing wrong?
I guess that explicit polymorphism is only used in queries, not for session.Get. But I couldn't find any references for this.
Try to not query for the base class, but always have an concrete subclass (which is in most cases a better design anyway):
public abstract class TestBase
{
public virtual int Id { get; set; }
public virtual string A { get; set; }
}
public class TestA : TestBase
{
public virtual string B { get; set; }
}
public class TestB : TestBase
{
public virtual string B { get; set; }
}
var a = this.Session.Get<TestA>(1);
Ok. I've got it. As Stefan supposed, i made abstract TestBase. But since I really needed to query TestBase table without many left joins, i introduced stub class:
public class TestStub : TestBase
{
// nothing
}
This class is absolutely empty. Map:
public sealed class TestStubMap : SubclassMap<TestStub>
{
public TestStubMap()
{
this.Table("TestBase");
this.KeyColumn("Id");
}
}
Now I can query:
var a = this.Session.Get<TestStub>(1)
It produces only one join (TestBase join TestBase). So now i can get my TestBase from db without overhead. I don't like hacks, but if built-in logic doesn't work (polymorphism=explicit), what is left to do.

NHibernate DuplicateMappingException when mapping abstract class and subclass

I have an abstract class and subclasses of this, and I want to map this to my database using NHibernate. I'm using Fluent and how to do the mapping. But when I add the mapping of the subclass an NHibernate.DuplicateMappingException is thrown when it is mapping. Why?
Here are my (simplified) classes:
public abstract class FieldValue
{
public int Id { get; set; }
public abstract object Value { get; set; }
}
public class StringFieldValue : FieldValue
{
public string ValueAsString { get; set; }
public override object Value
{
get
{
return ValueAsString;
}
set
{
ValueAsString = (string)value;
}
}
}
And the mappings:
public class FieldValueMapping : ClassMap<FieldValue>
{
public FieldValueMapping()
{
Id(m => m.Id).GeneratedBy.HiLo("1");
// DiscriminateSubClassesOnColumn("type");
}
}
public class StringValueMapping : SubclassMap<StringFieldValue>
{
public StringValueMapping()
{
Map(m => m.ValueAsString).Length(100);
}
}
And the exception:
> NHibernate.MappingException : Could not compile the mapping document: (XmlDocument)
----> NHibernate.DuplicateMappingException : Duplicate class/entity mapping NamespacePath.StringFieldValue
Any ideas?
Discovered the problem. It turned out that I did reference the same Assembly several times in the PersistenceModel used to configure the database:
public class MappingsPersistenceModel : PersistenceModel
{
public MappingsPersistenceModel()
{
AddMappingsFromAssembly(typeof(FooMapping).Assembly);
AddMappingsFromAssembly(typeof(BarMapping).Assembly);
// Where FooMapping and BarMapping is in the same Assembly.
}
}
Apparently this is not a problem for ClassMap-mappings. But for SubclassMap it doesn't handle it as well, causing duplicate mappings - and hence the DuplicateMappingException. Removing the duplicates in the PersistenceModel fixes the problem.
If you are using automappings together with explicit mappings then fluent can generate two mappings for the same class.

Fluent NHibernate: Example of a one-to-many relationship on an abstract class of a table-per-subclass implementation

I've been trying for ages to find an example (because I can't get it to work myself) of the correct mapping for a one-to-many relationship on an abstract class of a table-per-subclass implementation, in fluent nHibernate.
An example below: I'm looking to map the list of Fines on the Debt abstract base class to the Fine class.
If anyone knows of any tutorial or example they've come across before please let me know.
public abstract class Entity
{
public int Id { get; set; }
}
public abstract class Debt : Entity
{
public decimal Balance { get; set; }
public IList<Fine> Fines { get; set; }
public Debt()
{
Fines = new List<Fine>();
}
}
public class CarLoan : Debt
{
}
public class CreditCard : Debt
{
}
public class LoanApplication : Entity
{
public IList<Debt> ExistingDebts { get; set; }
public LoanApplication()
{
ExistingDebts = new List<Debt>();
}
}
public class Fine
{
public Int64 Cash { get; set; }
}
Can you tell us where exactly you're having difficulty? What have you tried?
Obviously, you'll need to declare all of your members as virtual (I assume this was an oversight in the example).
Basically, though, it would look like this:
public DebtMap : ClassMap<Debt>
{
public DebtMap()
{
Id(x => x.Id);
HasMany(x => x.Fines);
}
}
public FineMap : ClassMap<Fine>
{
public FineMap()
{
Id(x => x.Id);
// map other members
}
}
public CarLoanMap : SubclassMap<CarLoan> { }
public CreditCardMap : SubclassMap<CreditCard> { }

How to automap Table-per-class hierarchy in S#arp architecture

I am pretty new to S#harp architecture and fluent nhibernate. I was trying to build a sample solution using the template.
MappingIntegrationTest fails for me when I try to run it for the following domains
public class Component
{
public virtual string comp { get; set; }
}
public class Parent : Entity
{
public virtual string Type { get; set; }
}
public class Child1: Parent
{
public virtual Component Blah { get; set }
}
The ParentMap looks like following:
public class ParentMap : IAutoMappingOverride<Parent>
{
public void Override(AutoMapping<Parent> mapping)
{
mapping.DiscriminateSubClassesOnColumn("Type")
.SubClass<Child1>(m =>
{
m.Component(c => c.Blah, c =>
{
c.Map(x => x.comp , "comp");
}
}
}
}
The mapping integration tests fail for me
* Database was not configured through Database method.
----> NHibernate.MappingException : An association from the table Parent refers to an unmapped class: Component
Do I need to remove these classes from AutoMapper?