FluentNHibernate Unidirectional One-To-Many Mapping - nhibernate

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

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

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

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();

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 HasManytoMany Relation - It doesnt add into the link table

Using fluentnhibernate i am having a problem with the link table insertion.
Here is my entities
public partial class Item
{
public virtual int Id
{
get;
set;
}
public virtual string Description
{
get;
set;
}
public virtual IList<Category> Categories
{
get;
set;
}
}
public partial class Category
{
public virtual int Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual string Description
{
get;
set;
}
public virtual IList<Item> Items
{
get;
set;
}
}
Here is my mappings.
public class ItemMapping : ClassMap<Item>
{
public ItemMapping()
{
Table("Item");
Schema("dbo");
Id(x => x.Id);
Map(x => x.Description);
HasManyToMany(x => x.Categories)
.ChildKeyColumn("Item_id")
.ParentKeyColumn("Category_id")
.Table("CategoriesToItems")
.AsSet();
}
}
public class CategoryMapping : ClassMap<Category>
{
public CategoryMapping()
{
Table("Category");
Schema("dbo");
Id(x => x.Id);
Map(x => x.Description);
Map(x => x.Name);
HasManyToMany(x => x.Items)
.ChildKeyColumn("Category_id")
.ParentKeyColumn("Item_id")
.Table("CategoriesToItems")
.AsSet();
}
}
Here is how i add it to collection in my mvc page
var category = CategoryTask.Query(x => x.Id == post.Category).FirstOrDefault();
var item = new Item
{
Categories = new List<Category> { category },
Tags = tags
};
ItemTasks.Save(item);
My question is why it doesnt add the relations in my link table "CategoriesToItems". The table is already in the database with Category_Id (FK, int, not null) and Item_Id (FK, int, not null).
Where is the problem? why it doesnt add it to relation table?
It's hard to say what's really wrong when we can't see what your ItemTasks.Save does under the covers. Are you wrapping your save in a transaction? If not, you should be.
You should call Session.Flush() just before the transaction.Commit() as well.
I am not certain if the problem has been solved, but it looks similar to my problem (fluentnhibernate hasmanytomany same identifier exception).
Also, it looks like your parent and child key columns are backward.