How to map NHibernate custom collection with fluentNHibernate? - nhibernate

I am trying to map the collection for two days without success. I also read all possible articles and forums but still down there. Ok, here is the problem:
1) The collection class contains a private field "_internalCollection" which is mapped with NHib.
2) The holding entity should expose the collection trough readonly property.
3) I want to avoid implementing NHibernate interface IUserCollectionType!!!
I did this with xml mapping and it work great. The WarehouseEntity is a collection Item. Warehouses is a readonly property in OrgEntity class.
<component name="Warehouses" class="Core.Domain.Collections.EntitySet`1[Core.Domain.OrgStructure.IWarehouseEntity,Core],Core">
<set name="_internalCollection" table="`WAREHOUSE`" cascade="save-update" access="field" generic="true" lazy="true" >
<key column="`WarehouseOrgId`" foreign-key="FK_OrgWarehouse" />
<!--This is used to set the type of the collection items-->
<one-to-many class="Domain.Model.OrgStructure.WarehouseEntity,Domain"/>
</set>
</component>
Any idea how can I do it with fluent NHibernate?
EDIT: Core.Domain.Collections.EntitySet`1 is base collection class. It provides basic functionality for working with collections and can fit any class which is IEntity interface.

Try:
HasMany(x => x.Warehouses)
.AsSet().KeyColumn("WarehouseOrgId")
.Access.CamelCaseField(Prefix.Underscore)
.ForeignKeyConstraintName("FK_OrgWarehouse");
Edit: I missed a key part of the question so here's another try:
Component(x => x.Warehouses, m =>
{
m.HasMany<Warehouse>(Reveal.Member<EntitySet<IWarehouseEntity>>("_internalCollection")
.AsSet().KeyColumn("WarehouseOrgId")
.ForeignKeyConstraintName("FK_OrgWarehouse");
});
I'm sure that's not it but hopefully it puts you on the right path. Also have a look using ComponentMap.
My advice is to avoid custom collections entirely. I replaced all of ours with extension methods on IEnumerable<T>.

Related

Exclude property from INSERT command in nhibernate

I have an entity with a property which I wish to be readonly - meaning that when I insert this entity to the DB, SqlServer will generate the property's value automatically so I need nhibernate to ignore this property when executing the INSERT command but retrieve it when selecting the entity.
Important note: this property isn't ID! I don't want NHibernate to initialize it using generator, SqlServer will do it by itself.
And another note: I use configuration mapping so no fluent mapping solutions please.
That functionality is supported. There are two attributes:
<property name="GeneratedBySql" insert="false" update="false" />
The same could be applied even for reference mapping
<many-to-one name="ReferenceGeneratedBySql" insert="false" update="false" />
If we want to use Mapping-by-Code we do have the same in places, see:
Mapping-by-Code - Property (by Adam Bar)
Snippet cited:
Property(x => x.Property, m =>
{
m.Column("columnName");
...
m.Update(false);
m.Insert(false);

NHibernate custom collection type

I'm having an entity object called Patient and this entity is having a property called Visits which is of type VisitsCollection.
VisitsCollections is a child class of IList<Visit> but it also adds some custom logic to the collection (like auto ordering, some validation, notifications, etc..).
I need to use the custom collection type as it adds some data to the entities that are added to the collection and performs some other paperwork transparently.
Now I want to map that in NHibernate, so I've created:
<list name="Visits" lazy="true" fetch="select">
<key foreign-key="PatientId" />
<index column="Timestamp" />
<one-to-many class="Visit" not-found="ignore"/>
</list>
I'm getting an exception:
Unable to cast object of type 'NHibernate.Collection.PersistentList' to type '...VisitsCollection'
Whenever I'm accessing the visits property.
I've also tried to map it this way:
<list name="Visits" lazy="true" fetch="select" collection-type="VisitsCollection">
<key foreign-key="PatientId" />
<index column="Timestamp" />
<one-to-many class="Visit" not-found="ignore"/>
</list>
but still, I'm getting this exception:
Custom type does not implement UserCollectionType: .....VisitsCollection
I don't want to inherit my VisitsCollection from any NHibernate type as the collection class is part of a framework that I want it to be DAL-agnostic (as it will be used in many scenarios - not only with a database).
Any ideas on how to map this, preserving the structure of my code?
Thanks in advance.
I never use custom collection types, mainly because I'm lazy. NHibernate wants you to use a IUserCollectionType I believe, which requires a bit of plumbing.
Rather than that, my first stop would be to look at using extension methods as discussed by Billly McCafferty. But you have code written so...
Alternatively, you could map your collection as a component as discussed here by Colin Jack. This might be easier for your scenario?
Also check this SO thread.
I also vote up not to use custom collections. Anyway, you can do it via component.
<component name="Warehouses" class="Core.Domain.Collections.EntitySet`1[Core.Domain.OrgStructure.IWarehouseEntity,Core],Core">
<set name="_internalCollection" table="`WAREHOUSE`" cascade="save-update" access="field" generic="true" lazy="true" >
<key column="`WarehouseOrgId`" foreign-key="FK_OrgWarehouse" />
<!--This is used to set the type of the collection items-->
<one-to-many class="Domain.Model.OrgStructure.WarehouseEntity,Domain"/>
</set>
How to map NHibernate custom collection with fluentNHibernate?
Just for reference, here is how you could do it using FluentNHibernate
Whether we should or should not create a custom collection type is a separate topic IMHO
public class PatientOverride : IAutoMappingOverride<Patient>
{
public void Override(AutoMapping<Patient> mapping)
{
mapping.Component(
x => x.Visits,
part =>
{
part.HasMany(Reveal.Member<VisitsCollection, IEnumerable<Visit>>("backingFieldName")) // this is the backing field name for collection inside the VisitsCollection class
.KeyColumn("PatientId")
.Inverse(); // depends on your use case whether you need it or not
});
}
}

NHibernate - Lazy Loaded Collection

Should a lazy loaded collection in NHibernate ever give me a NullReferenceException? I'm getting an exception in a method like the following:
public void Test(ISession session, int id)
{
var entity = session.Load<MyEntity>(id);
entity.LazyLoadedCollection.Add(SomeItem);
}
The call to LazyLoadedCollection is throwing. My mapping looks like:
<bag lazy="true" table="MyTable">
<key>
<column name="LazyLoadedCollection" />
</key>
<many-to-many class="LazyLoadedItem">
<column name="LazyLoadedItemId" />
</many-to-many>
</bag>
Is this the expected behavior in NHibernate?
It's hard to say without seeing your class, but one thing you may not have realized is that you need to populate each collection in your class's constructor.
NHibernate will replace these collections with its own at certain times, but you still need to make sure they're initially populated with a HashedSet<T>, List<T>, or something else depending on the interface you're using.
No it's not. This is a not a good way to ask a question on the internet.
And it's really impossible to give you a direction what to do if you don't post the code throwing the exception and tell us where the exception comes from.

nhibernate mapping Ilist with composite-element

I have been trying to work with DDD style for my e-commerce application. Most of my business logic are implemented using fake repositories. Now, I would like to use NHibernate to hook my Domain Model to a real database.
I have a class Order which contains a list of OrderLines object
public IList<OrderLine> OrderLines{ ... } //line 1
In my OrderLine class I have a reference to the parent Order as follows
2. public Order Order { set; get;} // line 2
According to my understanding, OrderLine is a Value class instead of an Entity class, so I will use the composite-element to do the mapping.
<bag name="OrderLines" table="OrderLines" lazy="true">
<key column="Order_ID"/> <!--This is where I got confused. line 3-->
<composite-element class="OrderLine">
<!-- class attribute required -->
<many-to-one name="Order" class="Order" column="Order_ID"/> <!--Do I need this? line 4-->
...
</composite-element>
</bag>
Note that in line 3, I created a key element for the mapping(syntax requires this). But since I have defined a reference to Order class in my OrderLine class(line 2), do I also need to create a mapping at line 4?
You don't need line#4.
You can find a great explanation on the subject in another thread at stackoverflow here: Nhibernate , collections and compositeid

How can I map a list of strings to my entity using NHibernate?

I've got two tables in my database: Articles and Tags
The Tags tables consist of ArticleID (foreign key) and a Tag (varchar).
Now I need to map an articles tags into a readonly collection on Article entity, either using IList Tags or ReadOnlyCollection Tags.
I've consulted the NHibernate reference material, but I can't seem to figure when to use Set, Bag and the other Nhibernate collections. I've seen examples using the ISet collection, but I really don't like to tie my entity classes to a NHibernate type.
How can I do the mapping in NHibernate?
edit: I ended up using a <bag> instead, as it doesn't require an index:
<bag name="Tags" table="Tag" access="nosetter.camelcase" lazy="false">
<key column="ArticleId" />
<element column="Tag" type="System.String" />
</bag>
The type of collection to use in your mapping depends on how you want to represent the collection in code. The settings map like so:
The <list> maps directly to an
IList.
The <map> maps directly to an IDictionary.
The <bag> maps to an IList. A does not completely comply
with the IList interface because the
Add() method is not guaranteed to
return the correct index. An object
can be added to a <bag> without
initializing the IList. Make sure to
either hide the IList from the
consumers of your API or make it
well documented.
The <set> maps to an Iesi.Collections.ISet. That
interface is part of the
Iesi.Collections assembly
distributed with NHibernate.
so if you want an IList to be returned, then you would use the <list> mapping. In your case, I'd probably map using the <list> mapping.