Nhibernate back reference loads in one-to-one relation - nhibernate

I Have one-to-one relation in my NHibernate mapping:
<many-to-one name="PersonProfile" not-null="true"
class="PersonProfile" column="profile" cascade="all" lazy="proxy"/>
...
<one-to-one name="Owner" class="Person" property-ref="PersonProfile"
constrained="true" lazy="proxy"/>
PersonProfile class have batch-size attribute set. When user.PersonProfile property is hit batch load triggers. But then, when Owner property is loaded it loads from database. Why?

Because one-to-one relations can not be lazy loaded (in some circumstances).
See this fine explanation: NHibernate: how to enable lazy loading on one-to-one mapping

Related

How to persist a subset of an object instead of the whole object?

I'm struggling with a NHibernate related problem where I could use some input.
Introduction:
I have a legacy database where the relational concepts have not really been applied.
In the database I have an OrderLine table which contains data for an order lines.
On top of that the table also contains all columns with Order specific information. This could for example be order number of a customer.
E.x. If i have 10 order lines - then I have 10 rows in my OrderLines table and each row has all the Order specific data e.g. order number or customer information.
I did not want to have the above structure in my code so a view was created for Orders so that I could map my Order in NHibernate which then has a set/bag of OrderLines which makes much more sense.
Mapping: (simplified)
<class name="Order" table="[view_Orders]">
<bag name="OrderLines">
</class>
<class name="OrderLine" table="OrderLines" />
The problem:
The complexity of the view makes it impossible to save to the view. When trying NHibernates throws this exception:
NHibernate.Exceptions.GenericADOException: could not insert: XXX ---> System.Data.SqlClient.SqlException: View or function 'view_Orders' is not updatable because the modification affects multiple base tables.
My NHibernate mapping is constructed as an Order object which has a "set or bag" of OrderLine objects. Ideally I would like NHibernate only to persist the set of OrderLine objects instead of the whole object.
Is there a way of achieving this? I have tried locking the object using different lock modes but it did not help me.
You can use mutable="false" to avoid the update and deletes as this article says:
Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor performance optimizations.
To avoid the insert you can use the following statement (Uses the proyection instead an insert command, dont forget use check="none"):
<sql-insert check="none">SELECT 1</sql-insert>
Here is a tested example:
<class name="Order" table="[view_Orders]" mutable="false">
<id name="OrderId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="GrandTotal"/> -->
<set name="OrderLines" lazy="true" inverse="true" cascade="all-delete-orphan">
<key column="OrderId"/>
<one-to-many class="OrderLine"/>
</set>
<sql-insert check="none">SELECT 1</sql-insert>
</class>
<class name="OrderLine" table="OrderLine">
<id name="OrderLineId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="OrderId"/>
<property name="GrandTotal"/>/> -->
</class>
In case I do understand your issue, the solution is surprisingly simple. We just would mark root object with dynamic-update="true"
<class name="Order" table="[view_Orders]" dynamic-update="true">
...
</class>
And then apply update="false" to every property or reference which we have in that Order class mapped to view:
...
<property name="Code" update="false"/>
...
<many-to-one name="Country" update="false />
But our collection will need the standard, even cascade mapping:
<class name="Order" table="[view_Orders]" dynamic-update="true">
<bag name="OrderLines"
lazy="true"
inverse="true"
batch-size="25"
cascade="all-delete-orphan" >
...
</bag>
... // other stuff is update="false"
</class>
And now code like this would do management of OrderLines, while not executing any updates on the root object Order
var session = ... // get ISession
// load root
var root = session.Get<Order>(123);
// if needed change existing line (pretend there is one)
root.OrderLines[0].Amount = 100;
// add new
var newOrder = ... // new order
root.OrderLines.Add(newOrder);
session.Save(root);
session.Flush();
And that is it. Cascade on the root object is doing what we need, while the update="false" is not updating it...
NOTE: Just interesting note - there is also class and collection
setting mutable="false", but it would not work here... as the
solution mentioned above (it is sad, because that would be more
elegant, but not working as expected...). See:
19.2.2. Strategy: read only
If your application needs to read but never modify instances of a persistent class, a read-only cache may be used. This is the simplest and best performing strategy. Its even perfectly safe for use in a cluster.
<class name="Eg.Immutable" mutable="false">

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.

Filter entities on mapping level in NHibernate

Let's say that I have and database table called People, and entity People. Let's say that I need a quick way to remove a subset of people from displaying everywhere in application. So I add IsDeleted column to People table, and set values in that column to 1.
In Entity Framework there's a mechanism that specifies that for instans of entities with value in column IsDeleted set to 1 shouldn't be fetched and mapping framework filters data automatically. Is is possible to achieve with NHibernate?
You can define where attribute in your class mapping.
where (optional) specify an arbitrary SQL WHERE condition to be used
when retrieving objects of this class
<class ... where="IsDeleted = 0">
If you are using Fluent NHibernate then just define this in mapping class:
Where("IsDeleted = 0");
NH's mapping by code should be similar to Fluent NHibernate's mapping.
You can create abstract class, e.g. PeopleBase, from which your People class will be derived and map your entity to it.
After that you can use discriminator like this (didn't check for correctness, but it should work):
<class name="YourNamespace.PeopleBase,YourNamespace" table="People">
// ...
<discriminator column="IsDeleted" type="boolean" />
// Properties...
// ...
<subclass name="YourNamespace.People, YourNamespace" discriminator-value="false">
</subclass>
</class>
In order to achieve what I wanted, I've created base class + two subclasses. This is the configuration:
subclasses with discriminator-value:
<subclass name="People" discriminator-value="null">
</subclass>
<subclass name="PeopleHistory" discriminator-value="not null">
<property name="MasterRowId" />
</subclass>
discriminator in base class:
<discriminator column="MasterRowId" />

In nHibernate, can I map an abstract base class to a collection?

I have a base class for content items in a CMS I'm building. It's currently marked abstract because I only want derived classes to be instantiated. Derived classes like BlogPost, Article, Photo, etc. are set up as a joined subclass to my ContentBase class in nHibernate.
I'm trying to set up a many-to-many mapping between this class and a Tag class. I want to have a collection of Tags on the ContentBase class, and a collection of ContentBase items on the tag class.
Will nHibernate allow me to map the abstract ContentBase class as a collection on the Tag class? I'm assuming not since it wouldn't be able to instantiate any instances of this class when reconstituting a Tag entity from the db. I really don't want to have to have to use a collection of content items per type (e.g. TaggedBlogPosts, TaggedArticles, etc.) on the Tag class.
The whole reason I'm doing this is because logically, a content item can have many tags, and 1 tag can belong to multiple content items. in order for nHibernate to manage the relationships for me in a mapping table, I believe I have to set up a many-to-many association and add the Tag to the ContentBase.Tags collection and then the content item to the Tags.TaggedContentItems collection before the mapping table entry is created in nHibernate.
Here are my mappings for reference:
<class name="CMS.Core.Model.Tag,CMS.Core" table="bp_Tags">
<id column="TagName" name="TagName" type="String" unsaved-value="">
<generator class="assigned" />
</id>
<bag name="_taggedContentList" table="bp_Tags_Mappings" inverse="true" cascade="save-update" lazy="true">
<key column="TagName" />
<many-to-many class="CMS.Core.Model.ContentBase,CMS.Core" column="Target_Id" />
</bag>
</class>
<class name="CMS.Core.Model.ContentBase,CMS.Core" table="bp_Content">
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="SubmittedBy" column="SubmittedBy" type="string" length="256" not-null="true" />
<property name="SubmittedDate" column="SubmittedDate" type="datetime" not-null="true" />
<property name="PublishDate" column="PublishDate" type="datetime" not-null="true" />
<property name="State" column="State" type="CMS.Core.Model.ContentStates,CMS.Core" not-null="true" />
<property name="ContentType" column="ContentType" type="CMS.Core.Model.ContentTypes,CMS.Core" not-null="true" />
<bag name="_tagsList" table="bp_Tags_Mappings" lazy="false" cascade="save-update">
<key column="Target_Id" />
<many-to-many class="CMS.Core.Model.Tag,CMS.Core" column="TagName" lazy="false" />
</bag>
...
<joined-subclass name="CMS.Core.Model.BlogPost,CMS.Core" table="bp_Content_BlogPosts" >
<key column="Id" />
<property name="Body" type="string" column="Body" />
<property name="Title" type="string" column="Title" />
</joined-subclass>
...
I would also assume that Hibernate would need to instantiate the base class, which makes sense, as there is data directly linked to it in the DB.
It looks like your data entities are in a separate assembly from your main application. The point of not instantiating the base is from a business point of view, so if you make the constructor internal to the Core assembly, does that accomplish what you want? If not, it may be helpful to ask yourself: who am I protecting this functionality from?
NHibernate should allow you to map the abstract class as a collection as long as you map the abstract class itself (it looks like you have).
An alternative is to change your strategy to the Table-per-class-hierachy approach. This puts all your content into a single table with a discriminator column to define the type of content. NHibernate knows how to materialize each content type based on the discriminator. The downside is that:
Each unique property of the concrete classes has to be of type nullable.
This table can get unwieldy if there are a lot of properties specific to each concrete class.
The table-per-class-hierachy is the preferred default mapping strategy (per NHibernate in Action). I would start with the approach and modify it to table-per-subclass when the need is certain.
A whole separate solution would be keep the mapping as is and rely on query to get the content by tag without worrying about the tags keeping a reference to a collection of content.

nHibernate 2.0 - mapping a composite-id *and* many-to-one relationship causes "invalid index" error

I have a problem. Imagine this data model:
[Person] table has: PersonId, Name1
[Tag] table has: TagId, TagDescription
[PersonTag] has: PersonId, TagId, IsActive
Since [PersonTag] isn't just a simple many-to-many join table, I have all three entities created in nHibernate (exactly like they are in the data model). PersonTag, therefore, needs a composite-id, which I have mapped to a class like this:
<composite-id name="PersonTagKey" class="PersonTagKey">
<key-property name="PersonId"></key-property>
<key-property name="TagId"></key-property>
</composite-id>
I want to traverse the object graph and be able to look at both the Person and Tag objects from a retrieved PersonTag object. So, I have properties on the PersonTag object to do that, mapped like this:
<many-to-one name="Person" column="PersonId" lazy="proxy" cascade="none" class="Person"/>
<many-to-one name="Tag" column="TagId" lazy="proxy" cascade="none" class="Tag"/>
When I try to create a PersonTag object and save it, I get an "Invalid index n for this SqlParameterCollection with Count=n" error. I know this is because I've mapped the PersonId and TagId properties twice, once for the composite-id, and once for the many-to-one relationship. If I don't map the many-to-one objects, then everything works fine.
Is there some way for me to be able to have a composite-id AND a many-to-one relationship based on the same column modeled in the same nHibernate entity?
Kay, here's the answer. Little-to-no documentation on this:
<composite-id name="PersonTagKey" class="PersonTagKey">
<key-many-to-one name="Person" column="PersonId" lazy="proxy" class="Person">
<key-many-to-one name="Tag" column="TagId" lazy="proxy" class="Tag"/>
</composite-id>
This will allow you to create a composite-id made up of the inverse of a many-to-one relationship.
Good hunting...