I have such a simple model:
public abstract class Entity
{
public virtual Guid Id { get; protected set; }
}
public class Post : Entity
{
public String Title { get ; set; }
public String Content { get; set; }
public DateTime Timestamp { get; set; }
public Byte[] Thumbnail { get; set; }
}
public class Blog : Entity
{
public String Title { get; set; }
public ISet<Post> Posts { get; set; }
}
Then I have such mappings:
BLOG
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true assembly="Application.Domain" namespace="Application.Domain.Entities">
<class name="Blog">
<!-- id generator -->
<id name="Id">
<generator class="guid.comb" />
</id>
<!-- properties/columns -->
<property name="Title" not-null="true" />
<!-- components/columns -->
<!-- associations -->
<set name="Posts" cascade="all">
<!-- key column? -->
</set>
</class>
</hibernate-mapping>
POST
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" assembly="Application.Domain" namespace="Application.Domain.Entities">
<class name="Blog">
<!-- id generator -->
<id name="Id">
<generator class="guid.comb" />
</id>
<!-- properties/columns -->
<property name="Title" not-null="true" />
<property name="Content" not-null="true" />
<property name="Timestamp" not-null="true"/>
<property name="Thmbnail" />
<!-- components/columns -->
<!-- associations -->
</class>
</hibernate-mapping>
How do I map one-to-many association (unidirectional)?
Thanks!
In the blog mapping file you need to define a one-to-many relation between the foreign key column that references the Blog entity in the post table say it is BlogId and you need to tell'em what class this one-to-many relation relates to, in your case this will be the Post class and you need to define it with it's fully qualified namespace that contains this class and a comma then the assembly name as following:
<set name="Posts" table="Post">
<key column="BlogId"/>
<one-to-many class="Application.Domain.Entities.Post, Application.Domain"/>
</set>
I think it's the same problem as described here.
And also, I think you have a mistake in mapping of the Post - class name shouldn't be Blog. Also, there's no relation from Post to Blog in your example.
Related
I am new to NHibernate. Just started learning NHibernate.
I am getting for run-time error with my C# code
NHibernate.PropertyAccessException was unhandled
Message=Invalid Cast (check your mapping for property type mismatches); setter of NHibernateDemo.Customer
InnerException: System.InvalidCastException
Message=Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericSet`1[NHibernateDemo.Order]' to type 'System.Collections.Generic.ISet`1[NHibernateDemo.Order]'.
Following is my C# code written for
public class Customer {
public Customer()
{
MemberSince = DateTime.UtcNow;
Orders = new HashSet<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual Location Address { get; set; }
public virtual ISet<Order> Orders { get; set; }
}
It's hbm file is as follow
<class name="Customer" table="Customer" lazy="true" >
<id name="Id">
<generator class="guid.comb" />
</id>
<property name="FirstName" />
<property name="LastName" />
<component name="Address" >
<property name="Street" />
<property name="City" />
<property name="State" />
<property name="Country" />
</component>
<set name="Orders" table="`Order`" order-by="Ordered desc">
<key column="CustomerId" />
<one-to-many class="Order" />
</set>
</class>
public class Order {
public virtual Guid Id { get; set; }
public virtual DateTime Ordered { get; set; }
public virtual DateTime Shipped { get; set; }
public virtual Location ShipAddress { get; set; }
public virtual Customer Customer { get; set; }
}
<class name="Order" table="`Order`">
<id name="Id">
<generator class="guid.comb" />
</id>
<property name="Ordered" />
<property name="Shipped" />
<component name="ShipAddress" >
<property name="Street" />
<property name="City" />
<property name="State" />
<property name="Country" />
</component>
<many-to-one name="Customer" column="CustomerId" />
</class>
If I change "set" section to "list" in Customer HBM file and do necessary changes in Customer class. Program is running correctly. Also if i remove "set" section from Customer HBM file; it is working.
Can you please help me to find what is wrong with "set" section of Customer HBM file?
Your mapping is almost correct, but the ISet interface is not from System namespace but from iesi library (distributed with NHibernate)
So you can reference iesi and change your mapping:
public virtual Iesi.Collections.Generic.ISet<Order> Orders { get; set; }
Or use the IList<>
and mapping with a bag
<bag name="Orders" table="`Order`" order-by="Ordered desc">
<key column="CustomerId" />
<one-to-many class="Order" />
</bag>
NOTE also do not forget to init the list, just in case that entity is created via new operator and NOT loaded by NHibernate
I have a one-to-one relationship between a Person class and an Employee. I expect the INSERT to cascade from the Person to the Employee. However, this does not happen. I've tried cascade='all' and cascade='save-update' on one-to-one relationship element, but it didn't work. I have also uploaded my entire source code on: http://bit.ly/gnkxBr (3.52 MB)
The structures of the my objects are as follows:
public class Person
{
public virtual Employee Employee { get; set; }
public virtual int Age { get; set; }
public virtual string Forename { get; set; }
public virtual string Surname { get; set; }
public virtual int PersonID { get; set; }
}
public class Employee
{
public virtual int PersonID { get; set; }
public virtual string PayRollNo { get; set; }
public virtual int Holidays { get; set; }
public virtual Person Person { get; set; }
}
Mapping files shown below:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Person, Employee.DAL" table="`Person`" >
<id name="PersonID" column="`PersonId`" type="int">
<generator class="native" />
</id>
<property type="string" name="Forename" column="`Forename`" />
<property type="string" name="Surname" column="`Surname`" />
<property type="int" name="Age" column="`Age`" />
<one-to-one name="Employee" class="Employee" cascade="all" />
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Employee, Employee.DAL" table="`Employee`" >
<id name="PersonID" column="`PersonId`">
<generator class="foreign">
<param name="property" >Person</param>
</generator>
</id>
<property type="string" length="30" name="PayRollNo" column="`PayRollNo`" />
<property type="int" name="Holidays" column="`Holidays`" />
<one-to-one name="Person" class="Person" constrained="true" />
</class>
</hibernate-mapping>
Put the session.Save() method in a transaction. Or use the session.Flush() method after calling the save method.
I have problem using Fluent Nhibernate, I have following model. When I try to save Hotel with has new Geography I getting foreign key exception, looks like Nhibenate fails to save data in correct order, is it something I can correct via Fluent Nhibernate ?
public class Geography {
public virtual int CityID { get; set; }
public virtual string CountryCode { get; set; }
}
public class Hotel
{
public virtual int HotelID { get; set; }
public virtual Geography City { get; set; }
}
Mapping
public class HotelMap : ClassMap<Hotel>
{
public HotelMap()
{
Id(x => x.HotelID)
.GeneratedBy
.Identity();
References(x => x.City, "CityId")
.Cascade.All();
}
}
public class GeographyMap : ClassMap<Geography>
{
public GeographyMap()
{
Id(x => x.CityID);
Map(x => x.CountryCode);
HasMany(a => a.Hotels)
.Cascade.All();
}
}
Added generated mappings
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Hotel" table="`Hotel`">
<id name="HotelID" type="System.Int32">
<column name="HotelID" />
<generator class="assigned" />
</id>
<many-to-one cascade="all" class="Geography" foreign-key="HotelGeography" name="City">
<column name="CityId" />
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Geography" table="`Geography`">
<id name="CityID" type="System.Int32">
<column name="CityID" />
<generator class="assigned" />
</id>
<bag cascade="all" inverse="true" name="Hotels" mutable="true">
<key>
<column name="HotelID" />
</key>
<one-to-many class="Hotel" />
</bag>
<property name="CountryCode" type="System.String">
<column name="CountryCode" />
</property>
</class>
</hibernate-mapping>
Try to specify identity generator for Geography class. If you want to have a database-generated unique identifier (like identity), you can accomplish that by adding .GeneratedBy.Native() to your Id(...) in GeographyMap class.
Add .Inverse() to the collection mapping.
For more details, have a look at http://nhibernate.info/doc/nhibernate-reference/collections.html#collections-onetomany and http://nhibernate.info/doc/nhibernate-reference/collections.html#collections-bidirectional
i have these 2 classes:
public class Category
{
IDictionary<string, CategoryResorce> _resources;
}
public class CategoryResource
{
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
and this is xml mapping
<class name="Category" table="Categories">
<id name="ID">
<generator class="identity"/>
</id>
<map name="Resources" table="CategoriesResources" lazy="false">
<key column="EntityID" />
<index column="LangCode" type="string"/>
<composite-element class="Aca3.Models.Resources.CategoryResource">
<property name="Name" column="Name" />
<property name="Description" column="Description"/>
</composite-element>
</map>
</class>
and i'd like to write it with Fluent.
I found something similar and i was trying with this code:
HasMany(x => x.Resources)
.AsMap<string>("LangCode")
.AsIndexedCollection<string>("LangCode", c => c.GetIndexMapping())
.Cascade.All()
.KeyColumn("EntityID");
but i dont know how to map the CategoryResource entity as a composite element inside the Category element.
Any advice ?
thanks
I think the mapping you're looking for is something like this:
HasMany<CategoryResource>(x => x._resources)
.AsMap<string>("LangCode")
.KeyColumn("EntityID")
.Table("CategoryResources")
.Component(x =>
{
x.Map(c => c.Name);
x.Map(c => c.Description);
})
.Cascade.All();
I want map my object model to NHibernate. There is one tricky part in my concept and I don't know if it is possible to do this in NHibernate.
I want to have a collection of trees. I have two classes (below, only important properties indicated). Component is a node of a tree and ComponentGroup is a collection of trees.
public class Component
{
public Component Parent { get; set; }
public IList<Component> SubComponents { get; set; }
public ComponentGroup Group { get; set; }
}
public class ComponentGroup
{
public IList<Component> Components { get; set; }
}
Now I want each Component to know which ComponentGroup it belongs to, so I need reference from every Component to ComponentGroup (Group property). But ComponentGroup should have only collection of root nodes (direct children) - Components collection. So this is something like one-to-half mapping ;) "one" side has reference only to some items from "many" side.
Do you have any ideas how to map something like this using NHibernate?
I'll give it a shot (generated with FluentNHibernate)
<class name="Component" table="`Component`" xmlns="urn:nhibernate-mapping-2.2">
<id name="ComponentId" type="Int32" column="ComponentId">
<generator class="identity" />
</id>
<many-to-one name="Parent" column="ParentId" />
<bag name="SubComponents">
<key column="ComponentId" />
<one-to-many class="NHibernateTests.Component, NHibernateTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
<many-to-one name="Group" column="GroupId" />
<class name="ComponentGroup" table="`ComponentGroup`" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" type="Int32" column="ComponentGroupId">
<generator class="identity" />
</id>
<bag name="Components">
<key column="ComponentGroupId" />
<one-to-many class="NHibernateTests.Component, NHibernateTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bag>
EDIT:
If you want all your Components to know their ComponentGroup then set on all of them the ComponentGroup .
And in ComponentGroup if you want all the root components only then change the bag to :
<bag name="Components" where="ParentId is null">
so you only get the root components