nHibernate mapping generic IDictionary - nhibernate

I've asked this elsewhere and not got any sensible reply
I'm trying to map an IDictionary. I have this mapping:
<class name="MyProject.Item, MyProject" table="Item">
<...>
<map name="Properties" access="property" table="ItemProperties" lazy="false">
<key column="ItemID" />
<index column="Idx" type="int" />
<element column="Value" type="System.Boolean, mscorlib"/>
</map>
I can persist data, but when the data is retrieved I get an nHibernate exception:
{"The value "0" is not of type "Project.PropertyType" and cannot be used in this generic collection. Parameter name: key"}
So it can't map to the enum, but why ? if I have a regular property that uses an enum, it works fine.
Is what I'm trying to do even possible ? I can't find much info on doing this.

Your mapping shows the key as an integer, not as an enum. To map the enum properly, use type="MyProject.Project.PropertyType, MyProject".
However, normally for an enum the best approach is to leave the type information out of the mapping file altogether and let NHib pick it up through reflection. My reading of the NHib source implies that if you are mapping into a generic IDictionary<K,V> then NHib should pick up the exact type of your key via reflection. IOW you still should be able to leave out the type attribute.

Related

NHibernate.Engine.ForeignKeys - Unable to determine if entity is transient or detached

I have this Instrument entity:
<class name="Instrument" table="Instruments" mutable="false">
<id name="ID" column="INSTRUMENT_ID" unsaved-value="0">
<generator class="assigned" />
</id>
<property name="....." />
<property name="....." />
</class>
This entity is used in many-to-one relationship in other entity (InstrumentSelection). This is many-to-one mapping info:
<many-to-one name="Instrument" access="field.camelcase" column="Instrument_ID" update="false" class="Instrument" not-null="true" fetch="join" lazy="false" />
The issue I've it that when I save InstrumentSelection entity with Save:
Transact(() => session.Save(entity));
I get error in logs:
2012-12-20 14:09:54,607 WARN 12 NHibernate.Engine.ForeignKeys - Unable
to determine if Instrument with assigned
identifier 11457 is transient or detached; querying the database. Use
explicit Save() or Update() in session to prevent this.
A few facts about Instrument entity:
It's just a reference entity
It's immutable entity
It can not be added / inserted via application. I get rows in database from external feed.
Question (version 1): A my question is: is there a way to instruct NHibernate to always consider Instrument entity as detached? I mean - if an instance of Instrument exists in application it means that it's present in database. So there is no too much sense in quering the database.
EDIT 1: Because Question (version 1) was not answered yet, let me change it slightly:
Question (version 2): What could be the behaviour that NHibernate is still trying to work out whether entity is detached/transient? I think I have my mapping configured correctly (unsaved-value, generator).
The problem is that when you save the InstrumentSelection, NHibernate is cascading the operation to save the child Instruments. My first suggestion is to set cascade to none on the InstrumentSelect side of the relationship.
My second suggestion is to use an interceptor as shown in this answer.

NHibernate Composite Index, not a key

Still a n00b in NHibernate :(
I want to add a composite index to the hbm.xml of one of my POCOs, for performance purposes. It does not relate directly to a class, but rather two common values I will be querying against.
I think I need to do a <map></map> entry in the XML, but the XSD is asking for a class name on the composite-key element, and there is no direct relationship, per se... plus it's asking for more information than I think I would need to provide. How do I do this?
<map name="PropertyKeys">
<key>
<column name="StockID" />
<column name="PropertyName" />
</key>
<composite-index class="Something?">
<key-property name="What goes here?" />
</composite-index>
<what else goes here?>
</map>
Have you read this http://ayende.com/blog/4045/nhibernate-mapping-map It explains when you would use a map and further on it explains the composite-index
However without more background info it is not 100% certain that you need a map!

Preventing Nhibernate from persisting a specific collection in a class

I have a Sponsor object which has a collection that looks like this...
public virtual IDictionary<SettingId, object> SettingValueDefaults { get; set; }
These are actually being pulled as a subset of a larger table. I need to be able to read from these, and that is working correctly.
However, I would like to be able to make run-time changes to this collection, and have nhibernate ignore those changes, or even trying to persist the collection at all.
Again, I need nhibernate to retreive the data, so I can use it in code, but not persist the data changes I make to the collection during execution.
The mapping for this collection is below :
<map name="SettingValueDefaults" cascade="none">
<cache usage="read-write" region="Sponsors" />
<key not-null="true" column="SponsorId"/>
<index column="SettingId" type="HealthTools.Core.Domain.Model.Sponsor.Settings.SettingId, HealthTools.Core"/>
<element column="DefaultValue" type="HealthTools.Infrastructure.DataAccess.SqlVariant, HealthTools.Infrastructure"/>
<loader query-ref="GetDefaultSettingValues" />
</map>
Here is the error I am receiving from Nhibernate when tries to persist the Sponsor object.
"Invalid object name 'HealthTools.dbo.SettingValueDefaults"
This is occuring because there is no SettingsValueDefaults table, the map is just pulling data from the Sponsor.Settings table via the GetDefaultSettingValues function.
You'll want to make it read-only:
<map name="SettingValueDefaults" cascade="none" access="readonly">

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.