Fluent Nhibernate 3 Mapping Composite Field (Custom Type) - fluent-nhibernate

HI all, my scenario
public class Permission
{
public virtual Function Function { get; set; }
public virtual Profile Profile { get; set; }
}
public class MapPermission : ClassMap<Permission>
{
public MapPermission()
{
Table("Permissions".ToUpper());
CompositeId().KeyProperty(x => x.Function, "FunctionID").KeyProperty(x => x.Profile, "ProfileID");
}
}
Where Function AND Profile are two easy mapped entities. When i Run i have this error:
Could not determine type for: Data.Model.Entities.Function, Data.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(FunctionID)"}
Is there a way to avoid this? ultimately i need to create a class with CompositeID made by two custom mapped classes. If i uses compositeID with int fields it works like a charm
Thanks in Advance
Function (Like Profile) Mapping
public class Function
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
}
public class MapFunction : ClassMap<Function>
{
public MapFunction()
{
Table("FUNCTIONS");
Id(x => x.ID);
Map(x => x.Name);
}
}

Use KeyReference instead of KeyProperty
public class MapPermission : ClassMap<Permission>
{
public MapPermission()
{
Table("Permissions".ToUpper());
CompositeId()
.KeyReference(x => x.Function, "FunctionID")
.KeyReference(x => x.Profile, "ProfileID");
}
}

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")

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;

Trying to run query for entities when I have Inheritance with fluent Nhibernate

I attempted to extract some common properties to a base class and map with Fluent Nhibernate. In addition, I also attempted to add a second level of inheritance.
//Base entity class
public class EntityBase : IEntityBase
{
public EntityBase()
{
CreatedDate = DateTime.Now;
}
public virtual DateTime? CreatedDate { get; set; }
public virtual int Id { get; set; }
public virtual int Version { get; set; }
}
//Base Entity Mapping
public class EntityBaseMap: ClassMap<EntityBase>
{
public EntityBaseMap()
{
UseUnionSubclassForInheritanceMapping();
Id(x => x.Id);
Version(x => x.Id);
Map(x => x.CreatedDate);
}
}
//first sub class of EntityBase
public class Actuate : EntityBase, IActuate
{
public virtual DateTime? ActivatedOn { get; set; }
}
//Actuate Mapping class
public class ActuateMap : SubclassMap<Actuate>
{
public ActuateMap()
{
Map(x => x.ActivatedOn);
}
}
//Sub class entity
public class Item : Actuate
{
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual decimal UnitPrice { get; set; }
public virtual ItemStatus Status { get; set; }
public virtual Store Store { get; set; }
}
//Item Mapping class
public class ItemMap : SubclassMap<Item>
{
public ItemMap()
{
Abstract();
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.UnitPrice);
Map(x => x.Status);
References(x => x.Store);
}
}
The entity I have discovered has a problem (other relationship issues might exists)
//Store entity Does not inherit from EntityBase or Actuate
public class Store
{
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual string Name { get; set; }
public virtual IEnumerable<Item> Items { get; set; }
}
//Store mapping class
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id).GeneratedBy.Assigned();
Version(x => x.Version);
Map(x => x.Name);
HasMany(x => x.Items);
}
}
Problem
If I try to run the following query:
//store = is the Store entity I have retrieved from the database and I am trying
//trying to return the items that are associated with the store and are active
store.Items != null && store.Items.Any(item => item.Status == ItemStatus.Active);
I get the following error:
ERROR
Nhibernate.Exceptions.GenericADOException: could not initialize a collection: [SomeDomain.Store.Items#0][SQL: SELECT items0_.StoreId as StoreId1_, items0_.Id as Id1_, items0_.Id as Id10_0_, items0_.CreatedDate as CreatedD2_10_0_, items0_.ActivatedOn as Activate1_11_0_, items0_.Name as Name12_0_, items0_.Description as Descript2_12_0_, items0_.UnitPrice as UnitPrice12_0_, items0_.Status as Status12_0_, items0_.StoreId as StoreId12_0_ FROM [Item] items0_ WHERE items0_.StoreId=?]"}
Inner Exception
"Invalid object name 'Item'."
Now, if I take out the base classes and Item doesn't inherit, and the
Id, Version
columns are part of the Item entity and are mapped in the ItemMap mapping class (with the ItemMap class inheriting from ClassMap<Item> instead, everything works without issue.
NOTE
I have also attempted to add on the StoreMap class unsuccessful.
HasMany(x => x.Items).KeyColumn("Id");
Any thoughts?
if entityBase is just for inheriting common properties then you do not need to map it at all
public class EntityBaseMap<TEntity> : ClassMap<TEntity> where TEntity : EntityBase
{
public EntityBaseMap()
{
Id(x => x.Id);
Version(x => x.Version);
Map(x => x.CreatedDate);
}
}
public class ActuateMap : EntityBaseMap<Actuate> { ... }
Notes:
Versionmapping should map Version property not Id
Version should be readonly in code so nobody accidently alters it
.KeyColumn("Id") is wrong because the column is from the Items table and then it's both the autogenerated id and foreign key. That's not possible nor usefull
usually only classes which are abstract should containt Abstract() in the mapping

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

Composite Key/Id Mapping with NHibernate

I have the following tables in my database:
Announcements:
- AnnouncementID (PK)
- Title
AnouncementsRead (composite PK on AnnouncementID and UserID):
- AnnouncementID (PK)
- UserID (PK)
- DateRead
Users:
- UserID (PK)
- UserName
Usually I'd map the "AnnouncementsRead" using a many-to-many relationship but this table also has an additional "DateRead" field.
So far I have defined the following entities:
public class Announcement
{
public virtual int AnnouncementID { get; set; }
public virtual string Title { get; set; }
public virtual IList<AnnouncementRead> AnnouncementsRead { get; private set; }
public Announcement()
{
AnnouncementsRead = new List<AnnouncementRead>();
}
}
public class AnnouncementRead
{
public virtual Announcement Announcement { get; set; }
public virtual User User { get; set; }
public virtual DateTime DateRead { get; set; }
}
public class User
{
public virtual int UserID { get; set; }
public virtual string UserName { get; set; }
public virtual IList<AnnouncementRead> AnnouncementsRead { get; private set; }
public User()
{
AnnouncementsRead = new List<AnnouncementRead>();
}
}
With the following mappings:
public class AnnouncementMap : ClassMap<Announcement>
{
public AnnouncementMap()
{
Table("Announcements");
Id(x => x.AnnouncementID);
Map(x => x.Title);
HasMany(x => x.AnnouncementsRead)
.Cascade.All();
}
}
public class AnnouncementReadMap : ClassMap<AnnouncementRead>
{
public AnnouncementReadMap()
{
Table("AnnouncementsRead");
CompositeId()
.KeyReference(x => x.Announcement, "AnnouncementID")
.KeyReference(x => x.User, "UserID");
Map(x => x.DateRead);
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
HasMany(x => x.AnnouncementsRead)
.Cascade.All();
}
}
However when I run this I receive the following error:
"composite-id class must override Equals(): Entities.AnnouncementRead"
I'd appreciate it if someone could point me in the right direction. Thanks
You should do just what NHibernate is telling you. AnnouncementRead should override Equals and GetHashCode methods. They should be based on fields that are part of primary key
When implementing equals you should use instanceof to allow comparing with subclasses. If Hibernate lazy loads a one to one or many to one relation, you will have a proxy for the class instead of the plain class. A proxy is a subclass. Comparing the class names would fail.
More technically: You should follow the Liskows Substitution Principle and ignore symmetricity.
The next pitfall is using something like name.equals(that.name) instead of name.equals(that.getName()). The first will fail, if that is a proxy.
http://www.laliluna.de/jpa-hibernate-guide/ch06s06.html