fluent NHibernate: many-to-many relationship with Product to Product - fluent-nhibernate

fluent NHibernate: many-to-many relationship with Product to Product.how i can implement it on asp.net mvc
public class Product
{
public virtual int Id { get; set; }
public virtual IList<Product> ManyProduct { get; set; }
}
Mapping
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.Id);
Map(x => x.ImageUrl);
}
HasManyToMany(x => x.ManyProduct)
.Cascade.All()
.Table("ProductInProduct");
}

You don't specifically say what is wrong but your HasManyToMany definition needs to specify the Parent and Child Id columns from your ProductInProduct table:
HasManyToMany(x => x.ManyProduct)
.Table("ProductInProduct")
.ParentKeyColumn("ParentId")
.ChildKeyColumn("ChildId")
.Cascade.All();

Related

NHibernate - Self referencing mapping interferes with foreign key mapping

I have the following classes:
public class Track
{
public virtual int Id { get; set; }
public virtual Track MainMix { get; set; }
public virtual IEnumerable<Track> SubMixes { get; set; }
public virtual IList<FileVersion> Files { get; set; }
}
public class FileVersion
{
public virtual int Id { get; set; }
public virtual Track Track { get; set; }
}
And the following mappings:
public class TrackMap : ClassMap<Track>
{
public TrackMap()
{
Id(x=>x.Id);
References(x => x.MainMix);
HasMany(x => x.SubMixes)
.Inverse()
.Cascade.All()
.KeyColumn("MainMix_id");
HasMany(a => a.Files)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.All();
}
}
public class FileVersionMap : ClassMap<FileVersion>
{
public FileVersionMap()
{
Id(x => x.Id);
References(x => x.Track);
}
}
There is omitted code for the sake of simplicity. The Track table has a "MainMix_id" column that is a self referencing column for a parent/child relationship among Track records.
When I try to fetch a track from the database the NHProfiler tells me that Nhibernate tries to fetch the fileversions of that track with the following query:
SELECT files0_.MainMix_id as MainMix9_1_,
files0_.Id as Id1_,
files0_.Id as Id9_0_,
files0_.Track_id as Track8_9_0_
FROM [FileVersion] files0_
WHERE files0_.MainMix_id = 3 /* #p0 */
It seems like it has confused the parent id column of the Track table with its primary key column. When I remove References(x => x.MainMix) from the Track mapping the query is correct, but I don't have the parent track record returned.
Let me know if I can clarify this any more and thanks in advance for your help!
Does this make a difference?
TrackMap :
References(x => x.MainMix).Column("MainMix_id");
FileVersionMap :
References(x => x.Track).Column("Track_id");

NHibernate Many to Many mapping Invalid Column arbitrary [table]_[id]

Ok. I have read a lot of similar situations but all of them seems to be more related to one-to-many mappings.
long story short... Here is the code.
public class Roles
{
public virtual int RoleID { get; protected set; }
public virtual Guid RoleGUID { get; protected set; }
public virtual string RoleName { get; protected set; }
public virtual string RoleDescription { get; protected set; }
public virtual IList<User> Users { get; protected set; }
}
public class RolesMap:ClassMap<Roles>
{
public RolesMap()
{
Table("Web_Roles");
Id(x => x.RoleID);
Map(x => x.RoleDescription);
Map(x => x.RoleName);
Map(x => x.RoleGUID);
HasManyToMany(x => x.Users)
.Cascade.All()
.Inverse()
.Table("Web_UserRoles");
}
}
public class User
{
public virtual int UserID { get; protected set; }
public virtual string UserName { get; protected set; }
public virtual string Password { get; protected set; }
public virtual string Email { get; protected set; }
public virtual Guid UserGUID { get; protected set; }
public virtual IList<Roles> Roles { get; protected set; }
}
public class UserMap: ClassMap<User>
{
public UserMap()
{
Table("Web_User");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
Map(x => x.UserGUID);
Map(x => x.Email);
HasManyToMany(x => x.Roles)
.Cascade.All()
.Table("Web_UserRoles");
}
}
public class UserRoles
{
public virtual int RoleID { get; protected set; }
public virtual int UserID { get; protected set; }
}
So, that's the domain entities and their respectives mappings. Not biggie. Of course, no mapping for UserRoles since it's only a "mapping table".
When i get my User I get the following error.
could not initialize a collection: [FamilyDerm.AUTH.Domain.User.Roles#1][SQL: SELECT roles0_.UserID as UserID1_, roles0_.Roles_id as Roles4_1_, roles1_.RoleID as RoleID1_0_, roles1_.RoleDescription as RoleDesc2_1_0_, roles1_.RoleName as RoleName1_0_, roles1_.RoleGUID as RoleGUID1_0_ FROM Web_UserRoles roles0_ left outer join Web_Roles roles1_ on roles0_.Roles_id=roles1_.RoleID WHERE roles0_.UserID=?]
It doesn't take much to realize that the mapping is converting RoleID from my "mapping entity" UserRoles to Roles_id, which I don't understand why. I am following NHibernate exact "way" but i don't seem to get it straight.
If I replace in SQL Server Roles_id by RoleID, it works like a charm. Obviously I am having either a naming convention issue or a mapping issue itself.
As I write this, i see questions popping out to my right with similar concerns but none of them offer a solution to my problem.
Thank you.
Because you haven't explicitly declared the field names in the Web_UserRoles table nHibernate infers them by adding an _Id to the name of the child collection so
HasManyToMany(x => x.Users)
.Cascade.All()
.Inverse()
.Table("Web_UserRoles");
will infer a field named Users_Id in the Web_UserRoles table and likewise Roles_Id from your HasManyToMany Roles mapping.
Modifying your HasManyToMany definitions to explicitly define the Parent and Child Id columns from your ProductInProduct table should sort your issue:
HasManyToMany(x => x.Users)
.Cascade.All()
.Inverse()
.Table("Web_UserRoles")
.ParentKeyColumn("UserId")
.ChildKeyColumn("RoleId");
and
HasManyToMany(x => x.Roles)
.Cascade.All()
.Table("Web_UserRoles")
.ParentKeyColumn("RoleId")
.ChildKeyColumn("UserId");

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

Getting records back from many to many fluent nhibernate?

I made a many to many relationship by following the fluent nhibernate Getting started tutorial .
(source: fluentnhibernate.org)
Now I am not sure how to retrieve data. For instance what happens if I want to get all the products a store carries.
So I would need to use the storeId on the products table. Yet there is no storeId in the products table and I don't have a class that actually contains mapping or properties for StoreProduct.
So I can't go
session.Query<StoreProduct>().Where(x => x.StoreId == "1").toList();
So do I need to do a join on Store and Products and then do a query on them?
Edit
Here is a watered down version of what I have.
public class Student
{
public virtual Guid StudentId { get; private set; }
public virtual IList<Course> Courses { get; set; }
public virtual IList<Permission> Permissions{get; set;}
public Student()
{
Courses = new List<Course>();
Permissions = new List<Permission>();
}
public class StudentMap : ClassMap<Student>
{
public StudentMap()
{
Table("Students");
Id(x => x.StudentId).Column("StudentId");
HasManyToMany(x => x.Permissions).Table("PermissionLevel");
HasManyToMany(x => x.Courses).Table("PermissionLevel");
}
}
public class CourseMap : ClassMap<Course>
{
public CourseMap()
{
Table("Courses");
Id(x => x.CourseId).Column("CourseId");
HasManyToMany(x => x.Permissions ).Table("PermissionLevel");
HasManyToMany(x => x.Students).Table("PermissionLevel");
}
}
public class Course
{
public virtual int CourseId { get; private set; }
public virtual IList<Permission> Permissions { get; set; }
public virtual IList<Student> Students { get; set; }
public Course()
{
Permissions = new List<Permission>();
Students = new List<Student>();
}
}
public class PermissionMap : ClassMap<Permission>
{
public PermissionMap()
{
Table("Permissions");
Id(x => x.PermissionId).Column("PermissionId");
HasManyToMany(x => x.Students).Table("PermissionLevel");
}
}
public class Permission
{
public virtual int PermissionId { get; private set; }
public virtual IList<Student> Students {get; set;}
public Permission()
{
Students = new List<Student>();
}
}
var a = session.Query<Student>().Where(x => x.Email == email).FirstOrDefault();
var b = session.Get<Student>(a.StudentId).Courses;
error what I get when I look into b.
could not initialize a collection:
[Student.Courses#757f27a2-e997-44f8-b2c2-6c0fd6ee2c2f][SQL:
SELECT courses0_.Student_id as
Student3_1_, courses0_.Course_id as
Course1_1_, course1_.CourseId as
CourseId2_0_, course1_.Prefix as
Prefix2_0_, course1_.BackgroundColor
as Backgrou3_2_0_ FROM PermissionLevel
courses0_ left outer join Courses
course1_ on
courses0_.Course_id=course1_.CourseId
WHERE courses0_.Student_id=?]"
No, you don't. StoreProduct is special table that hold many-to-many relations between Store and Products. NHibernate able to populate Store's collection of products using this table automatically. It should be described in mapping. You should query just like this:
var storeProducts = session.Get<Store>(1).Products;
Here's mapping for Store:
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Staff)
.Inverse()
.Cascade.All();
HasManyToMany(x => x.Products)
.Cascade.All()
.Table("StoreProduct");
}
}
Notice line HasManyToMany(x => x.Products) and .Table("StoreProduct") they tell NHibernate to use table StoreProduct as source for many-to-many relation store objects in collection Products.
You have wrong mappings for Student:
HasManyToMany(x => x.Permissions).Table("PermissionLevel");
HasManyToMany(x => x.Courses).Table("PermissionLevel");
It should be following:
HasManyToMany(x => x.Courses).Table("StudentCourses");
And you Student class is incomplete.

FluentNHibernate Unidirectional One-To-Many Mapping

I have two classes. One is Order:
public class Order
{
public virtual int Id { get; set; }
public virtual IList<Product> Products { get; set; }
}
The other one is Product:
public class Product
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
They are fluently mapped like this:
public class OrderMap : ClassMap<Order>
{
public OrderMap()
{
Table("Orders");
Id(x => x.Id, "Id");
HasMany(x => x.Products)
.KeyColumn("OrderId")
.Cascade.All();
}
}
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Table("Products");
Id(x => x.Id, "Id");
Map(x => x.Name);
}
}
The database does NOT have a not-null constraint on the OrderId column of the Products table.
Problem is: both the order and the products are being persisted, however the products are being persisted with a null value on the OrderId column.
Am I missing something?
instead of HasMany just use Reference
Reference(x => x.Products).Cascade.All();
Inverse on HasMany is an NHibernate term, and it means that the other end of the relationship is responsible for saving.
Well, as strange as it seems, we solved this issue here by re-working our Session management, using it to create an ITransaction in a using statement. Odd, but solved. Thanks everyone!
Try using:
HasMany(x => x.Products)
.KeyColumn("OrderId")
.Inverse()
.Cascade.All();
Which(Inverse()) states that OrderId is on the Products table