Fluent Nhibernate: Mapping Issue - fluent-nhibernate

I am very much new to Fluent Nhibernate. I am stuck with the one situation.
Please find bellow details about it.
Our table structure is like as
Table Student { Student_Id, Name}
Table School { School_Id, Name}
Table LinkTable { School_Id, Student_Id}
LinkTable contains only id of the Student and School. [Composite Key]
Relation is like
1) One student can be part of 0 or 1 School.
2) One School can contains many students.
Can anyone please let me know how the mapping will be done for each file?
or let mw know what is wrong in following mapping files
Right now, it is giving me error that Student Property is not found on SchoolStudent.
public Student()
{
Id(x => x.Id);
Map(x => x.Name);
HasOne(x => x.SchoolStudent).PropertyRef(r => r.Student);
}
public School()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.SchoolStudent).KeyColumn("School_Id").Inverse().Cascade.AllDeleteOrphan();
}
public SchoolStudent()
{
CompositeId().KeyReference(x => x.School, "School_Id")
.KeyReference(x => x.Student, "Student_Id");
}
Thanks,
Mahesh

I would re-write it to something like this:
Student.cs
public class Student
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<School> Schools { get; set; }
public Student()
{
Schools = new List<School>();
}
}
School.cs
public class School
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Student> Students { get; set; }
public School()
{
Students = new List<Student>();
}
}
StudentMap.cs
public class StudentMap : ClassMap<Student>
{
public Student()
{
Id(x => x.Id , "Student_Id");
Map(x => x.Name , "Name");
HasManyToMany(x => x.Schools).Table("LinkTable")
.ParentKeyColumn("Student_Id")
.ChildKeyColumn("School_Id");
}
}
SchoolMap.cs
public class SchoolMap: ClassMap<School>
{
public School()
{
Id(x => x.Id , "School_Id");
Map(x => x.Name , "Name");
HasManyToMany(x => x.Students).Table("LinkTable")
.ParentKeyColumn("School_Id")
.ChildKeyColumn("Student_Id");
}
}

If a student can only be associated with 0 or 1 schools, then you might consider dropping the LinkTable and the SchoolStudent class and just add School_Id to the Student table and a reference to School in the Student class.
Then your mappings are like:
public Student()
{
Id(x => x.Id);
Map(x => x.Name);
References(x => x.School);
}
public School()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Student).Inverse().Cascade.AllDeleteOrphan();
}

Related

fluent nhibernate, unable to resolve property: <property>

I have a one-to-one relationship in my db and I seem to be having issues with my fluent nhibernate mapping of this relationship.
When I attempt to insert a new TableA entity I receive the following error: "unable to resolve property: TableA". The error is thrown on this line in the repository: int id = (int)_session.Save(item);
Repository code:
public T Save(T item)
{
try
{
_session.BeginTransaction();
int id = (int)_session.Save(item);
_session.Transaction.Commit();
return _session.Get<T>(id);
}
catch (Exception)
{
_session.Transaction.Rollback();
throw;
}
}
Table definitions:
Table A
Id (int, pk, identity)
Field1 (nvarchar)
Field2 (date)
...
Table B
TableAId (int, pk) <-- no fk constraint on these tables
Field1 (nvarchar)
Field2 (nvarchar)
Field3 (bit)
Classes:
public class TableA
{
public virtual int Id {get;set;}
public virtual string Field1 {get;set;}
public virtual DateTime Field2 {get;set;}
public virtual TableB TableB {get;set;}
}
public class TableB
{
public virtual int TableAId {get;set;}
public virtual string Field1 {get;set;}
public virtual string Field2 {get;set;}
}
Mapping:
public class TableAMap : ClassMap<TableA>
{
public TableAMap(){
Id(x => x.Id);
Map(x => x.Field1);
Map(x => x.Field2);
HasOne(x => x.TableB)
.Cascade.SaveUpdate()
.Fetch.Join();
}
}
public class TableBMap : ClassMap<TableB>
{
public TableBMap()
{
Id(x => x.Id, "TableAId").GeneratedBy.Foreign("TableA");
Map(x => x.Field1);
Map(x => x.Field2);
Map(x => x.Field3);
}
}
I used these as a reference:
http://avinashsing.sunkur.com/2011/09/29/how-to-do-a-one-to-one-mapping-in-fluent-nhibernate/
One-to-one Mapping issue with NHibernate/Fluent: Foreign Key not updateing
IndexOutOfRangeException Deep in the bowels of NHibernate
I've been looking at this for so long now I fear I'm missing something simple (and stupid).
Update:
Tried this:
public class TableA
{
public virtual int Id {get;set;}
public virtual string Field1 {get;set;}
public virtual DateTime Field2 {get;set;}
public virtual TableB TableB {get;set;}
public virtual int TableBId
{
get{return TableB.Id;}
set{}
}
}
public class TableAMap : ClassMap<TableA>
{
public TableAMap()
{
Id(x => x.Id);
Map(x => x.Field1);
Map(x => x.Field2);
HasOne<TableB>(x => x.TableB)
.Cascade.SaveUpdate()
.Fetch.Join()
.ForeignKey("TableBId");
}
}
public class TableBMap : ClassMap<TableB>
{
public TableBMap()
{
Id(x => x.Id, "TableAId");
Map(x => x.Field1);
Map(x => x.Field2);
Map(x => x.Field3);
}
}
I didn't get the "unable to resolve property: TableA" error this time, but I received a different error. It seems like the Id of the TableA record did not cascade to the TableB record.
Did some more reading.
Found this post: fluent NHibernate one-to-one relationship?
Made some more changes:
public class TableAMap : ClassMap<TableA>
{
public TableAMap()
{
Id(x => x.Id);
Map(x => x.Field1);
Map(x => x.Field2);
HasOne<TableB>(x => x.TableB)
.Cascade.All()
.Constrained()
.Fetch.Join()
.ForeignKey("TableBId");
}
}
public class TableBMap : ClassMap<TableB>
{
public TableBMap()
{
Id(x => x.Id, "TableAId").UnsavedValue(0).GeneratedBy.Foreign("TableA");
Map(x => x.Field1);
Map(x => x.Field2);
Map(x => x.Field3);
HasOne<TableA>(x => x.TableA);
}
}
New error:
"attempted to assign id from null one-to-one property: TableA"
Even though this relationship is a one-to-one, and should be a one-to-one, I ended up modifying my database defintion to make this relationship a many-to-one and I mapped it as a many-to-one. Now it works. I'm not happy about it though, I think there should be a way to successfully map a one-to-one.
I was wasting too much time trying to get the one-to-one mapping to work and for the sake of my timeline I just needed to move on.

OneToOne mapping by code nhibernate 3.2

I'm trying to upgrade a project and use the build in code mapper.
I have 2 entities:
public class Person {
public virtual int Id { get; set; }
public virtual User User { get; set; }
}
public class User {
public virtual int Id { get; set; }
public virtual User Person { get; set; }
}
The database structure is like this:
table: users, fields: id
table: people, fields: id, userId
With FluentNHibernate i could map it like this:
public class UserMap : ClassMap<User> {
public UserMap() {
Id(x => x.Id).GeneratedBy.Identity();
HasOne(x => x.Person).PropertyRef("User").Not.LazyLoad();
}
}
public class PersonMap : ClassMap<Person> {
public PersonMap() {
Id(x => x.Id).GeneratedBy.Identity();
References(x => x.User).Column("UserId").Not.Nullable().Not.LazyLoad();
}
}
But is can't get it working with NH 3.2 build in code mapper.
This is what i have done so far.
OneToOne(x=>x.Person, m => {
m.PropertyReference(typeof(Person).GetProperty("User"));
});
OneToOne(x=>x.User, m => {});
Now the relation is mapped on User.Id and Person.Id but personid and userid can be different.
It's also possible that a user has no person.
from Users user0_ left outer join People person1_ on user0_.Id=person1_.Id
I think i have to specify that Person -> User is mapped with the UserId column but how?.
Since you were using References() in Fluent, you need to convert that to ManyToOne():
public class UserMap : ClassMapping<User>
{
public UserMap()
{
Id(x => x.Id, x => x.Generator(Generators.Identity));
OneToOne(x => x.Person,
x => x.PropertyReference(typeof(Person).GetProperty("User")));
}
}
public class PersonMap : ClassMapping<Person>
{
public PersonMap()
{
Id(x => x.Id, x => x.Generator(Generators.Identity));
ManyToOne(x => x.User,
x => x => { x.Column("UserId"); x.NotNullable(true); });
}
}
Two notes:
The type of User.Person should be Person, not user (that's probably just a bad edit)
.Not.LazyLoad() is almost always a bad idea. See NHibernate is lazy, just live with it

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.

Fluent Nhibernate Many-to-Many mapping with extra column

I want to map sth like this using fluent Nhibernate but I am not sure how to map the inventory table
This is the tables I have :
Product (Id,Name, ...)
Warehouse(Id, Name, ...)
Inventory(Product_id, Warehouse_id, StockInHand)
and Mappings like below
Public ProductMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.StoresStockedIn)
.Cascade.All()
.Inverse()
.Table("Inventory");
}
public WarehouseMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Products)
.Cascade.All()
.Table("Inventory");
}
The problem I face is that how can I map the StockInHand (how should the inventory model mapping?).
or are there other way to model this scenario ?
I have read some existing questions but not yet get clear understand what to do.
Thanks
Your relationship is not a many-to-many as far as NHibernate is concerned. A true many-to-many has no additional columns, such as StockInHand in your example.
You have to map this as two one-to-many relationships, and map Inventory as an entity.
Something like (i've skipped the other properties):
public class Product
{
public List<Inventory> Inventory { get; set; }
}
public class Warehouse
{
public List<Inventory> Inventory { get; set; }
}
public class Inventory
{
public Product Product { get; set; }
public Warehouse Warehouse { get; set; }
public bool StockInHand { get; set; }
}
public ProductMap() {
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Inventory)
.Cascade.All()
.Inverse()
.Table("Inventory");
}
public WarehouseMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Inventory)
.Cascade.All()
.Inverse()
.Table("Inventory");
}
public InventoryMap()
{
CompositeId()
.KeyReference(x => x.Product, "Product_id")
.KeyReference(x => x.Warehouse, "Warehouse_id")
Map(x => x.StockInHand);
}

NHibernate Mapping Question

I have tried various approaches to mapping the following structure, but I finally admit that after a day of not getting very far, I need some help.
So the question is, how would you guys go about mapping something like this. The schema is not fixed at this point.
public abstract class BaseObject
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string Prefix { get; set; }
public virtual string Suffix { get; set; }
public virtual BaseObject Parent { get; set; }
}
public class Room : BaseObject
{
public virtual int AreaId { get; set; }
}
public class Item : BaseObject
{
public virtual string Owner { get; set; }
public virtual IList<ItemAttribute> Attributes { get; set; }
public virtual int ItemTypeId { get; set; }
}
public class Potion : Item
{
public virtual int AmountLeft { get; set; }
}
Your input is very much appreciated.
This allows you to have it all in one table... doing this from memory, so syntax might not be exact.
public class ItemMap : ClassMap<BaseObject>
{
...
WithTable("objects");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
Map(x => x.Description);
...
DiscriminateSubClassesOnColumn("Type")
.SubClass<Room>("Room", x =>
{
x.Map(r => r.AreaId);
})
.SubClass<Item>("Item", c =>
{
i.Map(x => x.Owner);
i.References(x => x.Account).LazyLoad();
HasManyToMany(x => x.Attributes)
.WithParentKeyColumn("ItemId")
.WithChildKeyColumn("AttributeId")
.WithTableName("ItemAttributes")
.LazyLoad();
});
.SubClass<Potion>("Potion", x =>
{
x.Map(p => p.AmountLeft);
})
I would probably have a table for each class - Room, Item, Potion and then do fairly standard mappings for each.
I'd like to note that in my own experiences, it is a bad idea to name your Id field in your business objects "Id"
Here's a sample with Item, assoming some data names for your table.
public class ItemMap : ClassMap<Item>
{
public ItemMap()
{
WithTable("Items");
Id(x => x.Id, "ItemId").GeneratedBy.Identity();
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Prefix);
Map(x => x.Suffix);
Map(x => x.Owner);
Map(x => x.ItemTypeId);
References<Item>(x => x.Parent, "ParentItemId");
HasManyToMany(x => x.Attributes)
.WithParentKeyColumn("ItemId")
.WithChildKeyColumn("AttributeId")
.WithTableName("ItemAttributes")
.LazyLoad();
}
}
This is more than likely not be perfect - as I'm not sure how the mapping will work with the abstract parent.