Fluent Nhibernate: ignore interfaces/abstract classes during BuildSchema or UpdateSchema - fluent-nhibernate

Edit
I've got an interface that I'd like to base some classes on. When I go to BuildSchema (or UpdateSchema), Nhibernate creates a table for the interface. I thought I found a work-around as follows:
The Interface and Classes:
public interface ILevel
{
int Id { get; set; }
string Name { get; set; }
}
public abstract class Level : ILevel
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class LevelOne : Level { }
public class LevelTwo : Level { }
The Mappings:
public class LevelMap : ClassMap<ILevel>
{
public LevelMap()
{
Id(x => x.Id);
Map(x => x.Name);
}
}
public class LevelOneMap : SubclassMap<LevelOne>
{
}
public class LevelTwoMap : SubclassMap<LevelTwo>
{
}
This doesn't work (I did another UpdateSchema and the pesky ILevel table appeared).
Is there a configuration I'm unaware of to ignore interfaces/abstract classes altogether?

For seperate tables LevelOne and LevelTwo, that both have the properties of Level/ILevel, use a generic mapping for Level:
public abstract class LevelMap<T> : ClassMap<T>
where T : Level // ILevel should work, too
{
protected LevelMap()
{
Id(x => x.Id);
Map(x => x.Name);
}
}
public class LevelOneMap : LevelMap<LevelOne>
{
}
public class LevelTwoMap : LevelMap<LevelTwo>
{
}
You provide two separate class mappings without telling Fluent the real class hierarchy.

Related

Unable to cast object of type 'NHibernate.Mapping.List' to type 'NHibernate.Mapping.IKeyValue'

Trying to map a relationship in Fluent NHibernate and I'm getting this exception.
Here are the classes
public abstract class TaskContainer : DomainObject
{
public virtual IList<Task> Tasks { get; set; }
}
public class Task : TaskContainer
{
public virtual TaskContainer TaskContainer { get; set; }
public virtual string Description { get; set; }
public static Task Get(int id)
{
return Get<Task>(id);
}
}
And the mapping file
public class TaskMap : ClassMap<Task>
{
public TaskMap()
{
Id(x => x.Id);
Map(x => x.Description);
ReferencesAny(x => x.TaskContainer)
.EntityIdentifierColumn("TaskContainer_Id")
.EntityTypeColumn("TaskContainerDiscriminator")
.IdentityType<int>()
.AddMetaValue<Task>("Task")
HasMany(x => x.Tasks)
.KeyColumn("TaskContainer_Id")
.PropertyRef("Tasks")
.AsList();
}
}
I've seen other references to this error, but they had to do with implementing List<T> instead of IList<T>, which I am not doing.
Try: .PropertyRef("TaskContainer")

Different sequences for subclasses with Fluent NHibernate

I am using Fluent NHibernate and table per concrete class for inheritance mappings.
There is an abstract base class and two other subclasses.
My base class has Id column. Created tables are ok. All tables has its own Id column. But sequence is only one for these two tables.
I want to assign different sequence for every subclass.
public abstract class Base
{
public virtual int Id { get; set; }
}
public class BaseMap : ClassMap<Base>
{
public BaseMap()
{
Id(x => x.Id).GeneratedBy.Native();
}
}
public class A : Base
{
public virtual int AmountOfA { get; set; }
}
public class AMap : ClassMap<A>
{
public AMap()
{
Map(x => x.AmountOfA );
}
}
public class B : Base
{
public virtual int AmountOfB { get; set; }
}
public class BMap : ClassMap<B>
{
public BMap()
{
Map(x => x.AmountOfB );
}
}
Is this possible with Fluent NHibernate?
this is by design.
session.Get<Base>(1); would have undefined behavior because the id is not unique
consider the case when there is a reference to the base class Reference(x => x.SomeBase); with a the value 1 in the database: it would not be possible to know if A(Id: 1) or B(Id: 1) is the object referenced
if Base is only there to reuse the Id property then dont map it as own entity but create a base class
public class BaseMap<T> : ClassMap<T> where T : Base
{
public BaseMap()
{
Id(x => x.Id).GeneratedBy.Native();
}
}
public class AMap : BaseMap<A>
{
public AMap()
{
Map(x => x.AmountOfA );
}
}

Fluent NHibernate: map list of abstract class with table per concrete class (union-subclass)

I'm having a problem with the following scenario.
My class structure is as follows:
public class Owner
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Vehicle> Vehicles { get; set; }
}
public abstract class Vehicle
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
}
public abstract class PoweredVehicle : Vehicle
{
public virtual string EngineType { get; set; }
}
public class Car : PoweredVehicle
{
public virtual int Doors { get; set; }
}
public class Truck : PoweredVehicle
{
public virtual long MaxLoad { get; set; }
}
public class Bicycle : Vehicle
{
public virtual int FrameSize { get; set; }
}
Fluent mappings:
public class OwnerMap : ClassMap<Owner>
{
public OwnerMap()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name);
HasMany(x => x.Vehicles);
}
}
public class VehicleMap : ClassMap<Vehicle>
{
public VehicleMap()
{
Id(x => x.Id).GeneratedBy.HiLo("10");
Map(x => x.Name);
UseUnionSubclassForInheritanceMapping();
}
}
public class PoweredVehicleMap : SubclassMap<PoweredVehicle>
{
public PoweredVehicleMap()
{
Map(x => x.EngineType);
Abstract();
}
}
public class CarMap : SubclassMap<Car>
{
public CarMap()
{
Map(x => x.Doors);
}
}
public class TruckMap : SubclassMap<Truck>
{
public TruckMap()
{
Map(x => x.MaxLoad);
}
}
public class BicycleMap : SubclassMap<Bicycle>
{
public BicycleMap()
{
Map(x => x.FrameSize);
}
}
I insert a Car and a Bicycle. When I try to insert an Owner with a list of Vehicle objects (with a Car and a Bicycle), I get the following error:
Exception: NHibernate.Exceptions.GenericADOException: could not insert
collection:
[NHibernateTest.Owner.Vehicles#8ace95bc-ad80-46d7-94c7-a11f012b67c6][SQL:
UPDATE "Vehicle" SET Owner_id = #p0 WHERE Id = #p1] --->
System.Data.SQLite.SQLiteException: SQLite error
Since I setup table per concrete class, why is NHibernate trying to update a non-existing table, which is representing the base class? Is this type of mapping not supported for this scenario?
Also, when I change from HasMany to HasManyToMany, this works fine.
In this case the only choice is Inverse() mapping. This means that the concrete Vehicle (Car, Bicycle) must care about the persistence of the relationship.
To enable this, extend the Vehicle class with new property:
public abstract class Vehicle
{
..
// new owner independent navigation property
public virtual Guid OwnerId { get; set; }
}
and extend mapping of the Vehicle
public VehicleMap()
{
..
Map(x => x.OwnerId).Column("Owner_id);
}
and finally invert persistence responsibility. Not the owner, but the collection item will care about correct Owner_id column changes (when concrete Vehicle insert/update is invoked).
(more about inverse: https://stackoverflow.com/a/1454445/1679310)
public OwnerMap()
{
..
HasMany(x => x.Vehicles)
.Inverse()
.Cascade.All();
}
When Vehicle is added into Owner's collection, its OwnerId must be also assigned:
owner.Vehicles.Add(car);
car.OwnerId = owner.Id;

Why doesn't this class hierarchy fluent mapping work?

What's wrong with my mapping shown below? Is this a problem with GeneratedBy.Foreign()? How should I use it cause my PK in UserTable(UID) is also the FK which refers to PersonTable PK(PID). I get the Duplicate class/entity mapping consoleMappingTest.SystemUser error. what do you suggest(be sure to look at database structure- no way to change it). thanks.
Inheritance structure:
public class Person
{
public virtual int ID { get; set; }
}
public class User:Person
{
public override int ID
{
get
{
return base.ID;
}
set
{
base.ID = value;
}
}
public virtual string Name { get; set; }
public virtual int Salary { get; set; }
}
public class SystemUser:User
{
public virtual int Password { get; set; }
}
Database structure:
for saving some info about person(some fields not shown here):
PersonTable(PID)
for saving User and all it's subclasses like system user:
UserTable(UID,Name,Salary,Type)
and here is my mapping:
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Table("PersonTable");
Id(x => x.ID, "PID").GeneratedBy.Assigned();//or HiLo-not important
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("UserTable");
DiscriminateSubClassesOnColumn("Type").Default("U");
Id(x => x.ID, "UID").GeneratedBy.Foreign("Person");//how should use this?
Map(x => x.Salary);
Join("PTable", j =>
{
j.KeyColumn("UID");
j.Map(x => x.Name);
});
}
}
public class SystemUserMap : SubclassMap<SystemUser>
{
public SystemUserMap()
{
DiscriminatorValue("SU");
Map(x => x.Password);
}
}
Foreign("") is meant to point to a Reference (Property with another mapped entity) from which the Id should be retrieved. You don't have a Reference to class Person named Person so you can't use it like this.
you already asked the same question with an answer. I know i didn't do it right first shot but would be nice if you told me what doesnt work with the latest edit or you dont like the solution befor asking the same question again

How to do inheritance in fluent NH without discriminator type column

I have 2 classes:
public class MyBaseClass
{
public virtual int Id { get; set; }
public virtual string BaseProperty { get; set; }
}
public class MyClass : MyBaseClass
{
public virtual string ChildProperty { get; set; }
}
I want to map each of them to its own table (fluent NH). How to do it with no discriminator type column added to [MyBaseClass] table? So I expect [MyBaseClass] table consists of BaseProperty and Id columns only, MyClass consists of Id, BaseProperty and ChildProperty columns.
Thanks
You can try to put IgnoreBase to on MyBaseClass. It will say for FNH to map those classes independently
I've just found this (http://wiki.fluentnhibernate.org/Fluent_mapping#Components):
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Child : Parent
{
public string AnotherProperty { get; set; }
}
If you wanted to map this as a
table-per-subclass, you'd do it like
this:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(x => x.Id);
Map(x => x.Name);
}
}
public class ChildMap : SubclassMap<Child>
{
public ChildMap()
{
Map(x => x.AnotherProperty);
}
}
So looks like this approach does not require any Db changes like adding special fields to my tables. The only problem is I do not know how to do the same in AutoMapping with Override statements. We do mapping this way:
public class AutoMappingConfiguration : DefaultAutomappingConfiguration
{
public override bool IsDiscriminated(Type type)
{
return true;
}
public override bool ShouldMap(Type type)
{
return type.In(typeof(MyBaseClass),typeof(MyClass),...)
}
...
}
FluentNHibernate.Automapping.AutoPersistenceModel Instance =
AutoMap.AssemblyOf<MyBaseClass>(new AutoMappingConfiguration())
.Override<MyBaseClass>(m =>
{
...
}
}
So I'm not sure how to apply SubClass instruction in my case. Any advise?
Thanks.