Mapping a backing field, that has a different type from the respective property, using Fluent NHibernate - nhibernate

I need to persist this class on database using Fluent NHibernate:
public class RaccoonCity
{
public virtual int Id { get; private set; }
public virtual DateTime InfectionStart { get; private set; }
private IList<Zombie> _zombies = new List<Zombie>();
public virtual IEnumerable<Zombie> Zombies
{
get { return _zombies; }
}
protected RaccoonCity()
{}
public RaccoonCity(DateTime startMonth)
{
InfectionStart = startMonth;
}
public virtual void AddZombie(Zombie z)
{
_zombies.Add(z);
}
}
The property has type IEnumerable to indicate that you shouldn´t use it to insert new items. The backing field is of IList to make it easy to insert new items from the own class.
Zombie is a simple class:
public class Zombie
{
public virtual int Id { get; private set; }
public virtual string FormerName { get; set; }
public virtual DateTime Infected { get; set; }
}
The map is the following:
public class RaccoonCityMap: ClassMap<RaccoonCity>
{
public RaccoonCityMap()
{
Id(x => x.Id);
Map(x => x.InfectionStart);
HasMany(x => x.Zombies)
.Access.CamelCaseField(Prefix.Underscore)
.Inverse()
.Cascade.All();
}
}
When I test this, the data is inserted in database, but the zombie´s foreign keys are empty, and the RaccoonCity instance has zero items on Zombies list.

You are declaring the relationship as Inverse, which means the Zombie and not the RacoonCity is responsible for maintaining the relationship.
Either add the corresponding reference to zombie and set it on the AddZombie method, or remove the Inverse (in that case, you'll see an INSERT with a null FK followed by an update).
Suggested reading: http://nhibernate.info/doc/nh/en/index.html#collections-onetomany

Found a post about it: https://web.archive.org/web/20090831052429/http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/08/15/a-fluent-interface-to-nhibernate-part-3-mapping.aspx
I had to implement the method
HasManyComponent by myself since it
was missing in the actual trunk of the
framework. That is, it was not
possible to map a collection of value
objects. But it has not been that hard
since the source base is really nice.
My changes will probably be integrated
into the framework soon.
And this one:
http://nhforge.org/blogs/nhibernate/archive/2008/09/06/a-fluent-interface-to-nhibernate-part-3-mapping-relations.aspx

Related

Nhibernate interceptors not picking up properties of base class

I'm converting from Fluent to Loquacious, and I've run in to an issue where my interceptors are not getting all the fields like I think they should. If I look at the OnSave function
public override Boolean OnSave(Object entity, Object id, Object[] state,
String[] propertyNames, IType[] types)
and take a look at the propertyNames the only items in there are the items that were explicitly mapped in the mapping file (in the example this would just be ID, Start, and End).
In my case though I have a base class which isn't mapped at all. Instead it's just contains properties that get filled out by the interceptors. This used to work in Fluent Nhibernate, but now that I've moved to Nhibernate 3.3 I can't get it to work anymore.
My classes/mapping look something like this
public class BaseAuditEntity
{
public virtual int ModifiedByUserID { get; set; }
public virtual DateTime LastModifiedTime { get; set; }
}
public class Foo : BaseAuditEntity
{
public virtual int ID { get; protected internal set; }
public virtual DateTime Start { get; protected internal set; }
public virtual DateTime End { get; protected internal set; }
}
public class FooMap: ClassMapping<Foo>
{
Id(x => x.ID, m => m.column("fooID"));
Property(x => x.Start, m => m.column("start"));
Property(x => x.End, m => m.column("end"));
}
Any ideas of how to get this work? I don't want to have to map this every class, and I didn't think I needed to map the BaseAuditEntity, at least with Fluent it wasn't needed.
you could make a base mapping class
public class BaseAuditEntityMapping<T> : ClassMapping<T> where T: BaseAuditEntity
{
ManyToOne(x => x.ModifiedByUser);
Property(x => x.LastModifiedTime);
}
public class FooMap: BaseAuditEntityMapping<Foo>

Fluent NHibernate with ManyToMany and Custom Link Table

I have the following schema, and when I delete one of the objects on one many side, it seems to be trying to delete the objects on the other many side. Am somewhat confused about the proper Cascade options to use, and I don't find Oren's brief description of them to be useful, so please don't quote those back.
public class Store {
public virtual IList<StoreProduct> StoreProducts { get; set; }
}
public class Product {
public virtual IList<StoreProduct> StoreProducts { get; set; }
}
public class StoreProduct {
public virtual Store Store { get; set; }
public virtual Product Product { get; set; }
public virtual Decimal Cost { get; set; } //this is why I have a custom linking class
}
In my mapping overrides, I have:
For Store:
mapping.HasMany(x => x.StoreProducts).Cascade.AllDeleteOrphan().Inverse;
For Product:
mapping.HasMany(x => x.StoreProducts).Cascade.AllDeleteOrphan().Inverse;
When I try to delete a Store that has associated StoreProducts, it seems that NHIbernate tries to delete not only the StoreProducts, but the Products.
Here are my conventions:
return c =>
{
c.Add<ForeignKeyConvention>();
c.Add<HasManyConvention>();
c.Add<HasManyToManyConvention>();
c.Add<ManyToManyTableNameConvention>();
c.Add<PrimaryKeyConvention>();
c.Add<ReferenceConvention>();
c.Add<EnumConvention>();
c.Add<TableNameConvention>();
c.Add<CascadeAll>();
c.Add(DefaultCascade.All());
};
HasManyConvention:
public void Apply(IOneToManyCollectionInstance instance)
{
instance.Key.Column(instance.EntityType.Name + "Fk");
instance.Cascade.AllDeleteOrphan();
instance.Inverse();
}
What am I doing wrong?
Thanks!
p.s.: I don't want to overwhelm people w/code, but can post more if needed.
Thanks, CrazyDart - I think that is among the things I tried without success. What I ended up doing was adding a StoreProducts override that looks like this:
public class StoreProductOverride: IAutoMappingOverride<StoreProduct>
{
#region IAutoMappingOverride<StoreProduct> Members
public void Override(AutoMapping<IndicatorStrategy> mapping)
{
mapping.References(x => x.Store).ForeignKey("StoreFk").Cascade.SaveUpdate();
mapping.References(x => x.Producty).ForeignKey("ProductFk").Cascade.SaveUpdate();
}
#endregion
}
Seems to work, but QA hasn't tried to break it yet (-:
You need to turn off the cascading on StoreProduct is my guess. Its hard to test without setting it up. I see the cascade on Store and Product, but turn it off on StoreProduct.

How to use Fluent NHibernate in N-Tier application?

I'm trying to adopt Fluent NHibernate with my project, currently I can get data from database, when I'm at application server, data is include its PK but when I return this data (as List) to client all of its PK is loose.
How can I fixed this problem?
Update
My POCO class is below: PKs are CountryCd and CityCd
public class coCity
{
public virtual string CountryCd { get; private set; }
public virtual string CityCd { get; private set; }
public virtual string CityNameTH { get; set; }
public virtual string CityNameEN { get; set; }
public virtual int DeliveryLeadTime { get; set; }
public virtual string CreateBy { get; set; }
public virtual DateTime CreateDate { get; set; }
public virtual string UpdateBy { get; set; }
public virtual DateTime UpdateDate { get; set; }
public override bool Equals(object obj)
{
return this.GetHashCode().Equals(obj.GetHashCode());
}
public override int GetHashCode()
{
return (this.CountryCd + this.CityCd).GetHashCode();
}
}
Mapping class:
public class coCityMap : ClassMap<coCity>
{
public coCityMap()
{
Table("coCity"); // this is optional
CompositeId()
.KeyProperty(x => x.CountryCd)
.KeyProperty(x => x.CityCd);
Map(x => x.CityNameTH);
Map(x => x.CityNameEN);
Map(x => x.DeliveryLeadTime);
Map(x => x.CreateBy);
Map(x => x.CreateDate);
Map(x => x.UpdateBy);
Map(x => x.UpdateDate);
}
}
Source code to get data at application server
public List<coCity> GetTest()
{
List<coCity> result = new List<coCity>();
var sessionFactory = CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
result = (List<coCity>)session.CreateCriteria(typeof(coCity)).List<coCity>();
}
return result;
}
When its still at application server data is retrieve correctly as image below
alt text http://img138.imageshack.us/img138/1071/serverside.png
However when this data transit back to client side all of its PKs is loose like below.
alt text http://img203.imageshack.us/img203/1664/clientside.png
First of all, this isn't a problem with Fluent NHibernate so:
Serializable must be used on your POCO's when you serialize them.
(from your comment) NHibernate keeps a reference of the object retrieved from the database to a cache (1-st level cache). While you serialize this 'managed' object the output of the serialization is an unmanaged object. Nhibernate does not detect that a an object exists in the db just because you set an value in a newly constructed object. You must get the object from the database and update its properties and call Update() or you work with pure sql with the object that returned from the client (yikes!).
Note that is irrelevant with this question: your Equals() implementation is really bad as it doesn't take into account types and depends only on GetHashCode value. If all your classes have this implementation you could run into trouble.
I think the problem is with that private setter on the PK's properties. Try changing that to public.
Either way, mark your entity with Serializable
A few comments:
As a general recomendation when using nhibernate is to avoid composite Ids. Create on your model a surrogate Id that is an identity column and enforce uniqueness of CityCd and CountryCd somewhere else
When passing data around client/server tiers, consider using DTOs to avoid some commong LazyInitializationExceptions problems.

Fluent nHibernate and mapping IDictionary<DaysOfWeek,IDictionay<int, decimal>> how to?

I have problem with making mapping of classes with propert of type Dictionary and value in it of type Dictionary too, like this:
public class Class1
{
public virtual int Id { get; set; }
public virtual IDictionary<DayOfWeek, IDictionary<int, decimal>> Class1Dictionary { get; set; }
}
My mapping looks like this:
Id(i => i.Id);
HasMany(m => m.Class1Dictionary);
This doesn't work. The important thing I want have everything in one table not in two. WHet I had maked class from this second IDictionary I heve bigger problem. But first I can try like it is now.
It's not currently possible to use nested collections of any type in NHibernate.
Instead, you should define your property as follows:
public virtual IDictionary<DayOfWeek, Class2> Class1Dictionary { get; set; }
And add a new class:
public class Class2
{
public virtual decimal this[int key]
{
get { return Class2Dictionary[key]; }
set { Class2Dictionary[key] = value; }
}
public virtual IDictionary<int, decimal> Class2Dictionary { get; set; }
}
This way, you can map both classes and dictionaries normally, and still access your dictionary as:
class1Instance.Class1Dictionary[DayOfWeek.Sunday][1] = 9.4

FluentNHibernate mapping for Dictionary

What is the best way of mapping a simple Dictionary property using Fluent NHibernate?
public class PersistedData
{
public virtual IDictionary<key, value> Dictionary { get; set; }
}
public class PersistedDataMap : ClassMap<PersistedData>
{
HasMany(x => x.Dictionary)
.Table("dict_table")
.KeyColumn("column_id")
.AsMap<string>("key")
.Element("value");
}
This will properly map Dictionary to table dict_table and use column_id to associate it to the base id.
As a side note, if you would like to use an Enum as the Key in the dictionary, it should be noted that NHibernate.Type.EnumStringType<MyEnum> can be used in place of the string in .AsMap<string> to use the string value instead of the Ordinal.
Using a simple class relationship such as the following:
public class Foo {
public virtual IDictionary<string, Bar> Bars { get; set; }
}
public class Bar {
public virtual string Type { get; set; }
public virtual int Value { get; set; }
}
You can map this with Fluent NHibernate in this way:
mapping.HasMany(x => x.Bars)
.AsMap(x => x.Type);
Where Bar.Type is used as the key field into the dictionary.
To map a list as a dictionary:
HasMany(x => x.Customers)
.AsMap();
I have not used it; so cannot give an example.
Have look at the wiki: Cached version of the page, Actual page I have given the cached version of the page as the site seems to be down.