tag:blogger.com,1999:blog-60514709957366936172024-02-20T21:33:17.993+02:00.NET Skirmishone more developer's blogAnonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-6051470995736693617.post-32404609502718505222013-11-28T00:40:00.001+02:002013-11-28T00:44:00.573+02:00NHibernate - How to map interfaces<div dir="ltr" style="text-align: left;" trbidi="on"><br />
<b>Problem</b><br />
<br />
If you try to map interface with property that have no setter you will get NHibernate.PropertyNotFoundException - Could not find a setter for property '<i>property-name</i>' in class '<i>class-name</i>' on configuration.BuildSessionFactory().<br />
<br />
<b>Salvation</b><br />
<br />
Let's look on the following interfaces<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
public interface IDeliverySchedule
{
DeliveryScheduleId Id { get; }
SupplierId SupplierId { get; }
string Code { get; }
ICollection<storeid> Stores { get; }
IEnumerable<ideliverypattern> Patterns { get; }
void AddPattern(IDeliveryPattern pattern);
void RemovePattern(IDeliveryPattern pattern);
IEnumerable<datetime> GetDeliveryDates(DateTime fromDate, DateTime toDate);
DateTime? GetNextDeliveryDate(DateTime lookupDate);
}
public interface IDeliveryPattern
{
IDeliverySchedule Schedule { get; }
string Code { get; }
DateTime FirstDate { get; set; }
DateTime? GetNextDelivery(DateTime lookupDate);
IEnumerable<datetime> GetDeliveryDates(DateTime firstDate, DateTime lastDate);
}
]]></script><br />
<br />
To map them I create IIdentified<TId> interface and my implementation classes of IDeliverySchedule and IDeliveryPattern will implement it too. So we have Id setter only in implementations, not in the model interfaces.<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
public interface IIdentified<tid>
{
TId Id { get; set; }
}
]]></script><br />
Now I map IIdentified<DeliveryScheduleId> but name it IDeliverySchedule.<br />
<script class="brush:xml" type="syntaxhighlighter"><![CDATA[
<class name="IIdentified`1[[System.Guid, mscorlib]]" abstract="true"
entity-name="IDeliverySchedule" >
<composite-id name="Id" class="DeliveryScheduleId" >
<key-property name="Value" column="Id" />
</composite-id>
</class>
]]></script><br />
The same trick for IDeliveryPattern<br />
<script class="brush:xml" type="syntaxhighlighter"><![CDATA[
<class name="IIdentified`1[[System.Guid, mscorlib]]" abstract="true"
table="DeliveryPattern" entity-name="IDeliveryPattern" >
<id name="Id" generator="guid" />
<discriminator column="Type" />
</class>
]]></script><br />
Then finally we map concrete subclasses<br />
<script class="brush:xml" type="syntaxhighlighter"><![CDATA[
<union-subclass name="DeliverySchedule" table="DeliverySchedule" extends="IDeliverySchedule">
<component name="SupplierId" class="SupplierId" update="false">
<property name="Value" column="SupplierId" not-null="true" update="false" />
</component>
<property name="Code" not-null="true" update="false" />
<set name="Stores" cascade="all-delete-orphan" table="DeliveryScheduleStore">
<key column="DeliveryScheduleId" foreign-key="none" />
<composite-element class="StoreId">
<property name="Value" column="StoreId" not-null="true" update="false" />
</composite-element>
</set>
<set name="Patterns" cascade="all-delete-orphan" inverse="true" >
<key column="ScheduleId" foreign-key="none" />
<one-to-many entity-name="IDeliveryPattern" />
</set>
</union-subclass>
<subclass name="WeeklyDeliveryPattern" discriminator-value="Weekly" extends="IDeliveryPattern">
<many-to-one name="Schedule" entity-name="IDeliverySchedule" foreign-key="none" column="ScheduleId" />
<property name="Code" />
<property name="FirstDate" />
</subclass>
<subclass name="MonthlyDeliveryPattern" discriminator-value="Monthly" extends="IDeliveryPattern">
<many-to-one name="Schedule" entity-name="IDeliverySchedule" foreign-key="none" column="ScheduleId" />
<property name="Code" />
<property name="FirstDate" />
</subclass>
]]></script><br />
And it magically works. <br />
Take attention that in <one-to-many> and <many-to-one> associations we reference entity-name, not a class.<br />
See full working sample on <a href="https://github.com/stanb/HowToMapInterfaces">GitHub</a><br />
<br />
Happy Hibernating</div>Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0tag:blogger.com,1999:blog-6051470995736693617.post-30300970006052185002012-12-01T19:23:00.000+02:002012-12-01T19:26:37.734+02:00Use of Castle.Windsor typed factory component selector<div dir="ltr" style="text-align: left;" trbidi="on">
Some times you need to create objects on the fly and you want their dependencies be resolved by DI container.<br />
Using <a href="http://docs.castleproject.org/Windsor.Typed-Factory-Facility-interface-based-factories.ashx">Windsor Typed Factory Facility</a> gives you ability to avoid using service locator. This technique described pretty well in documentation and I am not going to repeat it here. What I am going to talk is how to use typed factory component selector.<br />
Lets look on the following model<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://gist.github.com/f52aa46390b9c3b6c682" target="_blank"><img border="0" height="208" src="http://3.bp.blogspot.com/-2X68RaZtWhs/ULoogLz7YcI/AAAAAAAAANM/c61kEYc6Ang/s320/Model%255B15%255D" width="320" /></a></div>
<br />
We have here some sort of D&D game. Sword, Short Sword and Knife implements IWeapon. And Warrior and Thief implements ICharacter.<br />
I want to have ICharacterFactory with CreateCharachter method that receive string argument specifying what class of a character I want to create.<br />
<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
public interface ICharacterFactory
{
ICharacter CreateCharacter(string clazz);
}
]]></script><br />
<br />
so that I can use in code:<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
var character = factory.CreateCharacter("warrior");
]]></script><br />
<br />
To do this I will override DefaultTypedFactoryComponentSelector and provide it during registration of my ICharacterFactory<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
public class ClassSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return (string)arguments[0];
}
}
]]></script><br />
<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
public class GameInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<typedfactoryfacility>();
container.Register(
// register different weapons
Component.For<iweapon>().ImplementedBy<sword>().LifestyleTransient(),
Component.For<iweapon>().ImplementedBy<shortsword>().LifestyleTransient(),
Component.For<iweapon>().ImplementedBy<knife>().LifestyleTransient(),
// register warrior class
Component.For<icharacter>().ImplementedBy<warrior>().Named("Warrior").LifestyleTransient()
.DependsOn(Property.ForKey<iweapon>().Is<sword>()),
// register thief class
Component.For<icharacter>().ImplementedBy<thief>().Named("Thief").LifestyleTransient()
.DependsOn(
Property.ForKey("rightWeapon").Is<shortsword>(),
Property.ForKey("leftWeapon").Is<knife>()),
// register character factory
Component.For<icharacterfactory>().AsFactory(new ClassSelector())
);
}
}
]]></script><br />
Now, when thief character will be created he will hold short sword in his right hand and knife in the left. When we create warrior it have only one sword.<br />
<script class="brush:csharp" type="syntaxhighlighter"><![CDATA[
[TestMethod]
public void CreateCharacter()
{
var container = new WindsorContainer();
container.Install(new GameInstaller());
var factory = container.Resolve<icharacterfactory>();
var warrior = factory.CreateCharacter("warrior") as Warrior;
Assert.IsNotNull(warrior);
Assert.IsInstanceOfType(warrior.Weapon, typeof(Sword));
var thief = factory.CreateCharacter("thief") as Thief;
Assert.IsNotNull(warrior);
Assert.IsInstanceOfType(thief.RightWeapon, typeof(ShortSword));
Assert.IsInstanceOfType(thief.LeftWeapon, typeof(Knife));
}
]]></script><br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0tag:blogger.com,1999:blog-6051470995736693617.post-84037091311359008382012-11-13T11:42:00.002+02:002012-11-13T11:42:46.254+02:00MassTransit, first look<div dir="ltr" style="text-align: left;" trbidi="on">
<div>
In my last project we have used self made service bus for about 3.5 years. As for me, using service bus was the one of the best things that happend to the project. After some experience in the field I think I do understand what features I need. Also I regard that developing own service bus was a bad move. It has some gaps and we never had a time and resources to close them. Not sure if today's known ESB solutions was had all needed features 3.5 years ago. As I remember them was in a very <span class="hps">zygote</span> state, but any way... In my future projects I prefer to move to an existing and proven <strong>free open source</strong> that can fit my vision of how ESB should work. </div>
<div>
I am checking <a href="http://masstransit-project.com/" target="_blank">MassTransit</a> as the option and it looks mostly matching. I have to say that it's documentation lacks. Also some intresting to me features are in a very early state. But in general, MassTransit seems very promising.</div>
</div>
Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0tag:blogger.com,1999:blog-6051470995736693617.post-47163382845728695142012-11-06T11:55:00.000+02:002012-11-06T12:15:56.433+02:00NHibernate, bug in deep load of bags<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<span style="font-family: inherit;">Some days ago I write about performance difference between bag and set mapping of collections. But not all is so sunny with the bags. </span><span style="font-family: inherit;">Let's look on the following example.</span><br />
<a href="https://github.com/stanb/NHExperiments/blob/master/NHBugs/NHBug/NHSpecificTest/NH3317/Model.cs" target="_blank"><img alt="Model" border="0" height="166" src="http://lh4.ggpht.com/-ceQmJ0NB6HU/UJitdQqaYFI/AAAAAAAAAMw/5M-G26dbemc/Model_thumb%25255B3%25255D.png?imgmax=800" style="background-image: none; border: 0px currentColor; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="Model" width="563" /></a><br />
<br />
<div class="MsoNormal" style="direction: ltr; margin: 0cm 0cm 10pt; text-align: left; unicode-bidi: embed;">
<span style="font-family: inherit;">We have blogs that contains posts, and posts that contain comments. <span style="mso-spacerun: yes;"> </span>And we want to <a href="https://github.com/stanb/NHExperiments/blob/master/NHBugs/NHBug/NHSpecificTest/NH3317/MapBagOfBags.hbm.xml" target="_blank">map</a> Blog.Posts and Post.Comments associations as <bag><bag>.</bag></span></div>
<div class="MsoNormal" style="direction: ltr; margin: 0cm 0cm 10pt; text-align: left; unicode-bidi: embed;">
<span style="font-family: inherit;">Now let's create new blog. Then add four posts. Then add one comment to second post, two comments to third post and three comments to forth post. <span style="mso-spacerun: yes;"> </span>In total we added 7 comments to 4 posts.</span></div>
<div class="MsoNormal" style="direction: ltr; margin: 0cm 0cm 10pt; text-align: left; unicode-bidi: embed;">
<span style="font-family: inherit;">But when we try to fetch whole graph of blog with its posts and with their comments in one single query we get strange results. </span></div>
<span style="font-family: "Courier New", Courier, monospace;">session.Query<<span style="color: #3d85c6;">Blog</span>>()</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> .Where(b => b.Id == expected.Id)<br />
.FetchMany(b => b.Posts)<br />
.ThenFetch(p => p.Comments)<br />
.ToList().First();</span><br />
<span style="font-size: x-small;"> </span><span style="font-family: inherit;"></span><br />
<div class="MsoNormal" style="direction: ltr; margin: 0cm 0cm 10pt; text-align: left; unicode-bidi: embed;">
<span style="font-family: inherit;">Our blog have 7 posts instead of 4. SQL query returned 7 joined rows from the DB (as expected) but it seems that NHibernate did not transformed properly received results.</span></div>
<div class="MsoNormal" style="direction: ltr; margin: 0cm 0cm 10pt; text-align: left; unicode-bidi: embed;">
<span style="font-family: inherit;">If we map Blog.Posts as <set> <set> it works fine. So that issue appears only with bags.</set></span></div>
<div class="MsoNormal" style="direction: ltr; margin: 0cm 0cm 10pt; text-align: left; unicode-bidi: embed;">
<span style="font-family: "Calibri","sans-serif"; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: Arial; mso-bidi-language: HE; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><span style="font-family: inherit;">I have opened a <a href="https://nhibernate.jira.com/browse/NH-3317" target="_blank">bug</a> on <span style="font-family: inherit;">NHibernate's JIRA issue tracker</span>. There are <a href="https://github.com/stanb/NHExperiments/tree/master/NHBugs" target="_blank">tests</a> that I have provided.</span></span></div>
</div>
Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0tag:blogger.com,1999:blog-6051470995736693617.post-35568449716674900292012-11-04T09:31:00.000+02:002012-11-04T09:31:58.641+02:00NHibernate, Bidirectional vs Unidirectional associations<div dir="ltr" style="text-align: left;" trbidi="on">
I heard from some peoples that bidirectional association is evil. I don’t know where them sneezed it from. I am not going to take a side and discuss it here. I am going to tell you that your choice have influence on NHibernate behavior and your code’s performance. <br />
Lets start with bidirectional association.<br />
<a href="http://lh4.ggpht.com/-ll5tALNApGY/UJQIeowJBWI/AAAAAAAAAMQ/ZL-Qdp-sq1o/s1600-h/Model%25255B5%25255D.png"><img alt="Model" border="0" height="170" src="http://lh4.ggpht.com/-YhGdOFbPmx0/UJQIgEEvHRI/AAAAAAAAAMY/_Lhp-73kQ5g/Model_thumb%25255B3%25255D.png?imgmax=800" style="background-image: none; border: 0px currentColor; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="Model" width="380" /></a><br />
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Order</span>{
<span style="color: blue;">public virtual </span><span style="color: #2b91af;">Guid </span>Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual int </span>Version { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual </span><span style="color: #2b91af;">DateTime </span>OrderTime { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual </span><span style="color: #2b91af;">ICollection</span><<span style="color: #2b91af;">OrderLine</span>> OrderLines { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
}
<span style="color: blue;">public class </span><span style="color: #2b91af;">OrderLine</span>{
<span style="color: blue;">public virtual </span><span style="color: #2b91af;">Guid </span>Id { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual </span><span style="color: #2b91af;">Order </span>Order { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual string </span>ProductName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual decimal </span>Price { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public virtual int </span>Quantity { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
}</pre>
<br />
Order references a collection of order lines and each order line references it’s order. And I <a href="https://gist.github.com/e5ade12f089a70a6bc11">map</a> collection as <bag> with inverse=true option.<br />
Lets try to add a new order line to an existing order.<br />
<br />
<pre class="code"><span style="color: blue;">using </span>(<span style="color: blue;">var </span>session = sessionFactory.OpenSession())
<span style="color: blue;">using </span>(<span style="color: blue;">var </span>tx = session.BeginTransaction())
{
<span style="color: blue;">var </span>order = session.Get<<span style="color: #2b91af;">Order</span>>(id);
order.OrderLines.Add(<span style="color: blue;">new </span><span style="color: #2b91af;">OrderLine
</span>{
Order = order,
ProductName = <span style="color: #a31515;">"Product 1"</span>,
Price = 9.99M,
Quantity = 15
});
tx.Commit();
}</pre>
<br />
Take a look on what is going in the database<br />
<br />
<pre class="code"><span style="color: blue;">SELECT
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id0_0_</span><span style="color: grey;">,
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: blue;">Version as </span><span style="color: teal;">Version0_0_</span><span style="color: grey;">,
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">as </span><span style="color: teal;">OrderTime0_0_
</span><span style="color: blue;">FROM </span><span style="color: teal;">Orders order0_
</span><span style="color: blue;">WHERE </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id</span><span style="color: grey;">=</span><span style="color: teal;">@p0
</span><span style="color: blue;">INSERT INTO </span><span style="color: teal;">OrderLines </span><span style="color: grey;">(</span><span style="color: teal;">OrderId</span><span style="color: grey;">, </span><span style="color: teal;">ProductName</span><span style="color: grey;">, </span><span style="color: teal;">Price</span><span style="color: grey;">, </span><span style="color: teal;">Quantity</span><span style="color: grey;">, </span><span style="color: teal;">Id</span><span style="color: grey;">)
</span><span style="color: blue;">VALUES </span><span style="color: grey;">(</span><span style="color: teal;">@p0</span><span style="color: grey;">, </span><span style="color: teal;">@p1</span><span style="color: grey;">, </span><span style="color: teal;">@p2</span><span style="color: grey;">, </span><span style="color: teal;">@p3</span><span style="color: grey;">, </span><span style="color: teal;">@p4</span><span style="color: grey;">)
</span><span style="color: blue;">UPDATE </span><span style="color: teal;">Orders </span><span style="color: blue;">SET Version </span><span style="color: grey;">= </span><span style="color: teal;">@p0</span><span style="color: grey;">, </span><span style="color: teal;">OrderTime </span><span style="color: grey;">= </span><span style="color: teal;">@p1 </span><span style="color: blue;">WHERE </span><span style="color: teal;">Id </span><span style="color: grey;">= </span><span style="color: teal;">@p2 </span><span style="color: grey;">AND </span><span style="color: blue;">Version </span><span style="color: grey;">= </span><span style="color: teal;">@p3
</span></pre>
Works as expected. The last query is for aggregate root versioning.<br />
Now lets see what happens when we use model with unidirectional association. Little changes to <a href="https://gist.github.com/22389e2b65c1293939a0">code</a> and <a href="https://gist.github.com/9a6d4668e2af0fff37da">mapping</a>. And that’s what we got in the database.<br />
<br />
<pre class="code"><span style="color: blue;">SELECT
</span><span style="color: teal;">order2x0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id0_0_</span><span style="color: grey;">,
</span><span style="color: teal;">order2x0_</span><span style="color: grey;">.</span><span style="color: blue;">Version as </span><span style="color: teal;">Version0_0_</span><span style="color: grey;">,
</span><span style="color: teal;">order2x0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">as </span><span style="color: teal;">OrderTime0_0_
</span><span style="color: blue;">FROM </span><span style="color: teal;">Orders order2x0_
</span><span style="color: blue;">WHERE </span><span style="color: teal;">order2x0_</span><span style="color: grey;">.</span><span style="color: teal;">Id</span><span style="color: grey;">=</span><span style="color: teal;">@p0
</span><span style="color: blue;">SELECT
</span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId </span><span style="color: blue;">as </span><span style="color: teal;">OrderId1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id1_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">ProductName </span><span style="color: blue;">as </span><span style="color: teal;">ProductN2_1_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">Price </span><span style="color: blue;">as </span><span style="color: teal;">Price1_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">Quantity </span><span style="color: blue;">as </span><span style="color: teal;">Quantity1_0_
</span><span style="color: blue;">FROM </span><span style="color: teal;">OrderLines orderlines0_
</span><span style="color: blue;">WHERE </span><span style="color: teal;">orderlines0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId</span><span style="color: grey;">=</span><span style="color: teal;">@p0
</span><span style="color: blue;">INSERT INTO </span><span style="color: teal;">OrderLines </span><span style="color: grey;">(</span><span style="color: teal;">ProductName</span><span style="color: grey;">, </span><span style="color: teal;">Price</span><span style="color: grey;">, </span><span style="color: teal;">Quantity</span><span style="color: grey;">, </span><span style="color: teal;">Id</span><span style="color: grey;">)
</span><span style="color: blue;">VALUES </span><span style="color: grey;">(</span><span style="color: teal;">@p0</span><span style="color: grey;">, </span><span style="color: teal;">@p1</span><span style="color: grey;">, </span><span style="color: teal;">@p2</span><span style="color: grey;">, </span><span style="color: teal;">@p3</span><span style="color: grey;">)
</span><span style="color: blue;">UPDATE </span><span style="color: teal;">Orders </span><span style="color: blue;">SET Version </span><span style="color: grey;">= </span><span style="color: teal;">@p0</span><span style="color: grey;">, </span><span style="color: teal;">OrderTime </span><span style="color: grey;">= </span><span style="color: teal;">@p1 </span><span style="color: blue;">WHERE </span><span style="color: teal;">Id </span><span style="color: grey;">= </span><span style="color: teal;">@p2 </span><span style="color: grey;">AND </span><span style="color: blue;">Version </span><span style="color: grey;">= </span><span style="color: teal;">@p3
</span><span style="color: blue;">UPDATE </span><span style="color: teal;">OrderLines </span><span style="color: blue;">SET </span><span style="color: teal;">OrderId </span><span style="color: grey;">= </span><span style="color: teal;">@p0 </span><span style="color: blue;">WHERE </span><span style="color: teal;">Id </span><span style="color: grey;">= </span><span style="color: teal;">@p1</span></pre>
<br />
Dah!? What’s going on here?<br />
The second query ignoring that collection mapped as a bag and goes to bring us already existing order lines. Seems like a bug.<br />
Third query forgot to set reference from the new order line to the order. <br />
And fifth query fixes that mistake. And that update will be executed for each order line.<br />
It’s annoying. So, finally, we have at least two unnecessary queries when we decide to use unidirectional association.<br />
I don’t know why and what was going in the heads of NH programmers when them coded it (no offence), but that is what we have and we will use it for the win! Just know your tools and make right decisions.</div>
Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0tag:blogger.com,1999:blog-6051470995736693617.post-75250310215952426492012-11-02T12:53:00.002+02:002012-11-02T19:47:11.597+02:00NHibernate: the little-known difference between <set> and <bag><div style="text-align: left" dir="ltr" trbidi="on">Set is a collection of unique items. Bag is none unique collection of items. This restriction influences on set's and bag's behavior from a performance point of view. <br>Take a look on pretty simple <a href="https://gist.github.com/fed6dc3e81106702f2e0">model</a>:<br> <a href="http://lh3.ggpht.com/-LGexq2nZsiQ/UJQHGNqeVTI/AAAAAAAAAMA/jAqCT9Ulg8s/s1600-h/SupplierModel%25255B8%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="SupplierModel" border="0" alt="SupplierModel" src="http://lh6.ggpht.com/-GYjmAYp3qTY/UJQHHaVE0DI/AAAAAAAAAMI/ALYzgj0TDYY/SupplierModel_thumb%25255B6%25255D.png?imgmax=800" width="378" height="143"></a><br>We have a supplier with thousands of orders. Let's try to add new order to the supplier and see what happens in the database. <br><br><pre class="code"><span style="color: blue">using </span>(<span style="color: blue">var </span>session = sessionFactory.OpenSession())<br><span style="color: blue">using </span>(<span style="color: blue">var </span>tx = session.BeginTransaction())<br>{<br> <span style="color: blue">var </span>supplier = session.Get<<span style="color: #2b91af">Supplier</span>>(id);<br> supplier.Orders.Add(<span style="color: blue">new </span><span style="color: #2b91af">SupplierOrder <br> </span>{ <br> Supplier = supplier, <br> OrderTime = <span style="color: #2b91af">DateTime</span>.Now <br> });<br><br> tx.Commit();<br>}</pre><pre class="code"></pre>If we map the orders as a <strong><a href="https://gist.github.com/35bf55a337e481722ddc"><set></a></strong> then NHibernate produces the next sql queries:<br><br><pre class="code"><pre class="code"><span style="color: blue">SELECT<br> </span><span style="color: teal">supplier0_</span><span style="color: grey">.</span><span style="color: teal">Id </span><span style="color: blue">as </span><span style="color: teal">Id6_0_</span><span style="color: grey">, <br> </span><span style="color: teal">supplier0_</span><span style="color: grey">.</span><span style="color: teal">Name </span><span style="color: blue">as </span><span style="color: teal">Name6_0_ <br></span><span style="color: blue">FROM </span><span style="color: teal">Suppliers supplier0_ <br></span><span style="color: blue">WHERE </span><span style="color: teal">supplier0_</span><span style="color: grey">.</span><span style="color: teal">Id</span><span style="color: grey">=</span><span style="color: teal">@p0<br><br></span><span style="color: blue">SELECT<br> </span><span style="color: teal">orders0_</span><span style="color: grey">.</span><span style="color: teal">SupplierId </span><span style="color: blue">as </span><span style="color: teal">SupplierId1_</span><span style="color: grey">, <br> </span><span style="color: teal">orders0_</span><span style="color: grey">.</span><span style="color: teal">Id </span><span style="color: blue">as </span><span style="color: teal">Id1_</span><span style="color: grey">, <br> </span><span style="color: teal">orders0_</span><span style="color: grey">.</span><span style="color: teal">Id </span><span style="color: blue">as </span><span style="color: teal">Id7_0_</span><span style="color: grey">, <br> </span><span style="color: teal">orders0_</span><span style="color: grey">.</span><span style="color: teal">SupplierId </span><span style="color: blue">as </span><span style="color: teal">SupplierId7_0_</span><span style="color: grey">, <br> </span><span style="color: teal">orders0_</span><span style="color: grey">.</span><span style="color: teal">OrderTime </span><span style="color: blue">as </span><span style="color: teal">OrderTime7_0_ <br></span><span style="color: blue">FROM </span><span style="color: teal">SupplierOrders orders0_ <br></span><span style="color: blue">WHERE </span><span style="color: teal">orders0_</span><span style="color: grey">.</span><span style="color: teal">SupplierId</span><span style="color: grey">=</span><span style="color: teal">@p0<br><br></span><span style="color: blue">INSERT INTO </span><span style="color: teal">SupplierOrders </span><span style="color: grey">(</span><span style="color: teal">SupplierId</span><span style="color: grey">, </span><span style="color: teal">OrderTime</span><span style="color: grey">, </span><span style="color: teal">Id</span><span style="color: grey">) </span><span style="color: blue">VALUES </span><span style="color: grey">(</span><span style="color: teal">@p0</span><span style="color: grey">, </span><span style="color: teal">@p1</span><span style="color: grey">, </span><span style="color: teal">@p2</span><span style="color: grey">)<br></span></pre></pre>As we see it queries for the supplier row, its orders and then inserts new order. What happens if supplier already has thousands of orders? We fetch them all!<br>Let's try to map orders as a <strong><a href="https://gist.github.com/24150513ef8650220bb4"><bag></a></strong><br><br><pre class="code"><span style="color: blue">SELECT<br> </span><span style="color: teal">supplier0_</span><span style="color: grey">.</span><span style="color: teal">Id </span><span style="color: blue">as </span><span style="color: teal">Id6_0_</span><span style="color: grey">,<br> </span><span style="color: teal">supplier0_</span><span style="color: grey">.</span><span style="color: teal">Name </span><span style="color: blue">as </span><span style="color: teal">Name6_0_<br></span><span style="color: blue">FROM </span><span style="color: teal">Suppliers supplier0_ <br></span><span style="color: blue">WHERE </span><span style="color: teal">supplier0_</span><span style="color: grey">.</span><span style="color: teal">Id</span><span style="color: grey">=</span><span style="color: teal">@p0<br><br></span><span style="color: blue">INSERT INTO </span><span style="color: teal">SupplierOrders </span><span style="color: grey">(</span><span style="color: teal">SupplierId</span><span style="color: grey">, </span><span style="color: teal">OrderTime</span><span style="color: grey">, </span><span style="color: teal">Id</span><span style="color: grey">) </span><span style="color: blue">VALUES </span><span style="color: grey">(</span><span style="color: teal">@p0</span><span style="color: grey">, </span><span style="color: teal">@p1</span><span style="color: grey">, </span><span style="color: teal">@p2</span><span style="color: grey">)</span></pre><br>This one seems better. Now we just fetched supplier and inserted new order.<br><br>Take it into account when you choose between set and bag.<br><br><b>Pay attention. It behaves different if you are not using bidirectional association between master and detail classes. Also it behaves different when you map detail class as a composite-element. But that's another story.</b></div> Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0tag:blogger.com,1999:blog-6051470995736693617.post-37877015906552267142012-11-01T01:49:00.000+02:002012-11-02T19:39:02.512+02:00NHibernate, Paging and eager loading<div dir="ltr" style="text-align: left;" trbidi="on">
Q: How to fetch with NHibernate a page from a couple of master – detail tables?<br />
Let’s say we have a well known and simplified model of orders – order lines.<br />
<a href="http://lh4.ggpht.com/-LcHNpgHJJnY/UJG5Wml4YSI/AAAAAAAAALQ/q8aPdlNHH48/s1600-h/Model4.png"><img alt="Model" border="0" height="180" src="http://lh4.ggpht.com/-ZPSUfEg8osE/UJG5X63PoFI/AAAAAAAAALY/pqXCJGOs3R4/Model_thumb2.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="Model" width="412" /></a><br />
And we want to fetch a 3rd page (page size is 10) of the last orders received before specified day.<br />
The intuitive solution is just query orders table with outer join on order lines table using standard paging technics.<br />
<br />
<pre class="code"><span style="color: blue;">var </span>res = session.Query<<span style="color: #2b91af;">Order</span>>()
.Where(o => o.OrderTime < beforeDate)
.OrderByDescending(o => o.OrderTime)
.FetchMany(e => e.OrderLines)
.Skip(20)
.Take(10)
.ToList();</pre>
<br />
But when we look at results we see that we fetched less than 10 orders! What was happened here?<br />
Take a look on generated by NH sql:<br />
<br />
<pre class="code"><span style="color: blue;">SELECT TOP </span><span style="color: grey;">(</span><span style="color: teal;">@p0</span><span style="color: grey;">)
</span><span style="color: teal;">Id4_0_</span><span style="color: grey;">, </span><span style="color: teal;">Id5_1_</span><span style="color: grey;">, </span><span style="color: teal;">Version4_0_</span><span style="color: grey;">, </span><span style="color: teal;">OrderTime4_0_</span><span style="color: grey;">, </span><span style="color: teal;">OrderId5_1_</span><span style="color: grey;">, </span><span style="color: teal;">ProductN3_5_1_</span><span style="color: grey;">, </span><span style="color: teal;">Price5_1_</span><span style="color: grey;">, </span><span style="color: teal;">Quantity5_1_</span><span style="color: grey;">, </span><span style="color: teal;">OrderId0__</span><span style="color: grey;">, </span><span style="color: teal;">Id0__
</span><span style="color: blue;">FROM </span><span style="color: grey;">(
</span><span style="color: blue;">select
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id4_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: blue;">Version as </span><span style="color: teal;">Version4_0_</span><span style="color: grey;">,
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">as </span><span style="color: teal;">OrderTime4_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId </span><span style="color: blue;">as </span><span style="color: teal;">OrderId5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">ProductName </span><span style="color: blue;">as </span><span style="color: teal;">ProductN3_5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Price </span><span style="color: blue;">as </span><span style="color: teal;">Price5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Quantity </span><span style="color: blue;">as </span><span style="color: teal;">Quantity5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId </span><span style="color: blue;">as </span><span style="color: teal;">OrderId0__</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id0__</span><span style="color: grey;">,
</span><span style="color: magenta;">ROW_NUMBER</span><span style="color: grey;">() </span><span style="color: blue;">OVER</span><span style="color: grey;">(</span><span style="color: blue;">ORDER BY </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">DESC</span><span style="color: grey;">) </span><span style="color: blue;">as </span><span style="color: teal;">__hibernate_sort_row
</span><span style="color: blue;">from </span><span style="color: teal;">Orders order0_
</span><span style="color: grey;">left outer join </span><span style="color: teal;">OrderLines orderlines1_
</span><span style="color: blue;">on </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id</span><span style="color: grey;">=</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId
</span><span style="color: blue;">where </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime</span><span style="color: grey;"><</span><span style="color: teal;">@p1
</span><span style="color: grey;">) </span><span style="color: blue;">as </span><span style="color: teal;">query
</span><span style="color: blue;">WHERE </span><span style="color: teal;">query</span><span style="color: grey;">.</span><span style="color: teal;">__hibernate_sort_row </span><span style="color: grey;">> </span><span style="color: teal;">@p2</span></pre>
<pre class="code"><span style="color: blue;">ORDER BY </span><span style="color: teal;">query</span><span style="color: grey;">.</span><span style="color: teal;">__hibernate_sort_row</span></pre>
<br />
It firstly joins orders with their order lines so we have multiple lines per same order and only than takes a specified page. So we not only fetching less than 10 orders, but we also not actually skipping 20 orders. We are skipping and taking joined rows.<br />
As for me it’s a bug and not intended behavior.<br />
I have expected that it firstly will take a needed page of orders and only than will join result with order lines.<br />
So how anyway we can fetch a page of orders with their order lines in a most efficient way?<br />
There is the best solution that I have found:<br />
<br />
<pre class="code"><span style="color: blue;">var </span>subQuery = session.Query<<span style="color: #2b91af;">Order</span>>()
.Where(o => o.OrderTime < beforeDate)
.OrderByDescending(e => e.OrderTime)
.Select(o => o.Id)
.Skip(20)
.Take(10);
<span style="color: blue;">var </span>res = session.Query<<span style="color: #2b91af;">Order</span>>()
.FetchMany(e => e.OrderLines)
.Where(e => subQuery.Contains(e.Id))
.OrderByDescending(o => o.OrderTime)
.ToList();</pre>
<br />
I use sub query to find a needed page of orders and than fetch orders with its order lines by order’s ids present in the sub query.<br />
<br />
<pre class="code"><span style="color: blue;">select
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id4_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: blue;">Version as </span><span style="color: teal;">Version4_0_</span><span style="color: grey;">,
</span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">as </span><span style="color: teal;">OrderTime4_0_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId </span><span style="color: blue;">as </span><span style="color: teal;">OrderId5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">ProductName </span><span style="color: blue;">as </span><span style="color: teal;">ProductN3_5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Price </span><span style="color: blue;">as </span><span style="color: teal;">Price5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Quantity </span><span style="color: blue;">as </span><span style="color: teal;">Quantity5_1_</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId </span><span style="color: blue;">as </span><span style="color: teal;">OrderId0__</span><span style="color: grey;">,
</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: blue;">as </span><span style="color: teal;">Id0__
</span><span style="color: blue;">from </span><span style="color: teal;">Orders order0_
</span><span style="color: grey;">left outer join </span><span style="color: teal;">OrderLines orderlines1_
</span><span style="color: blue;">on </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id</span><span style="color: grey;">=</span><span style="color: teal;">orderlines1_</span><span style="color: grey;">.</span><span style="color: teal;">OrderId
</span><span style="color: blue;">where </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">Id </span><span style="color: grey;">in (
</span><span style="color: blue;">SELECT TOP </span><span style="color: grey;">(</span><span style="color: teal;">@p0</span><span style="color: grey;">) </span><span style="color: teal;">Id
</span><span style="color: blue;">FROM </span><span style="color: grey;">(
</span><span style="color: blue;">select </span><span style="color: teal;">order2_</span><span style="color: grey;">.</span><span style="color: teal;">Id</span><span style="color: grey;">,
</span><span style="color: magenta;">ROW_NUMBER</span><span style="color: grey;">() </span><span style="color: blue;">OVER</span><span style="color: grey;">(</span><span style="color: blue;">ORDER BY </span><span style="color: teal;">order2_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">DESC</span><span style="color: grey;">) </span><span style="color: blue;">as </span><span style="color: teal;">__hibernate_sort_row
</span><span style="color: blue;">from </span><span style="color: teal;">Orders order2_
</span><span style="color: blue;">where </span><span style="color: teal;">order2_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime</span><span style="color: grey;"><</span><span style="color: teal;">@p1
</span><span style="color: grey;">) </span><span style="color: blue;">as </span><span style="color: teal;">query
</span><span style="color: blue;">WHERE </span><span style="color: teal;">query</span><span style="color: grey;">.</span><span style="color: teal;">__hibernate_sort_row </span><span style="color: grey;">> </span><span style="color: teal;">@p2
</span><span style="color: blue;">ORDER BY </span><span style="color: teal;">query</span><span style="color: grey;">.</span><span style="color: teal;">__hibernate_sort_row
</span><span style="color: grey;">)
</span><span style="color: blue;">order by </span><span style="color: teal;">order0_</span><span style="color: grey;">.</span><span style="color: teal;">OrderTime </span><span style="color: blue;">desc</span></pre>
<br />
<br />
Pay attention. It does not work with 3.2 version of NH. In 3.2 version NH generates wrong SQL for Contains method. In our case it totally ignored sub select. The issue was fixed in the latest released version of NH: 3.3.1.4000.</div>
Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com1tag:blogger.com,1999:blog-6051470995736693617.post-16391950092482316672011-08-02T00:05:00.000+03:002011-08-02T00:08:42.862+03:00Upgrade to NHibernate 3.2.0<div style="text-align: left" dir="ltr" trbidi="on">Last days I have worked on upgrading our projects from NH 2.1.2 to a fresh 3.2.0. I am not going to write here about new features and all changes. You can read it in release notes. But I will list what changes I was need to do in an existing code that was written with NH 2.1.2. <br />1. Now only two dlls referenced. No more log4net, proxy factories (in my case it is Castle), antlr3 and external LINQ provider. That’s good. But why they till now depends on Iesi.Collections? <br /> <div style="text-align: left" dir="ltr" trbidi="on">2. NHibernate session factory configuration section become a little thinner: “proxyfactory.factory_class” and “use_outer_join” should be deleted. <br />3. I am very happy with a new LINQ provider but this is a little annoying to replace every where Linq<T>() with Query<T>(). <br />4. In old LINQ for eager loading was used Expand() method. <br /> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:7c1c12c2-aa47-4bfb-b561-17a26d241a30" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #fff; max-height: 300px; overflow: auto"> <ol style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">var</span> query = session.Linq<<span style="color:#2b91af">ActionItem</span>>();</li> <li style="background: #f3f3f3">query.Expand(<span style="color:#a31515">"Options"</span>);</li> <li>query.Expand(<span style="color:#a31515">"Options.Dependants"</span>);</li> <li style="background: #f3f3f3"><span style="color:#0000ff">var</span> actions = query.Where(a => a.Event.ID == eventID).ToList();</li> </ol> </div> </div> </div> <br />And now with NH 3.2 it should be replaced with four new methods: Fetch(), ThenFetch(), FetchMany() and ThanFetchMany(). <br /> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:c0048c9c-fc93-4616-a3b4-f80b886293e1" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #fff; max-height: 300px; overflow: auto"> <ol style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">var</span> actions = session.Query<<span style="color:#2b91af">ActionItem</span>>()</li> <li style="background: #f3f3f3"> .Where(a => a.Event.ID == eventID)</li> <li> .FetchMany(a => a.Options)</li> <li style="background: #f3f3f3"> .ThenFetchMany(o => o.Dependants)</li> <li> .ToList();</li> </ol> </div> </div> </div> <br />Tried it with QueryOver method. This is an ugly one :) <br /> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:d084d2bb-62a3-4005-b96b-7a22beff39f6" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #fff; max-height: 300px; overflow: auto"> <ol style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"> <li><span style="color:#2b91af">Option</span> optionAlias = <span style="color:#0000ff">null</span>;</li> <li style="background: #f3f3f3"><span style="color:#2b91af">ActionItem</span> actionAlias = <span style="color:#0000ff">null</span>;</li> <li><span style="color:#2b91af">ActionItem</span> dependantAlias = <span style="color:#0000ff">null</span>;</li> <li style="background: #f3f3f3"> </li> <li><span style="color:#0000ff">var</span> actions = session.QueryOver<<span style="color:#2b91af">ActionItem</span>>(() => actionAlias)</li> <li style="background: #f3f3f3"> .Where(a => a.Event.ID == eventID)</li> <li> .Left.JoinAlias(() => actionAlias.Options, () => optionAlias)</li> <li style="background: #f3f3f3"> .Left.JoinAlias(() => optionAlias.Dependants, () => dependantAlias)</li> <li> .TransformUsing(<span style="color:#2b91af">Transformers</span>.DistinctRootEntity)</li> <li style="background: #f3f3f3"> .List();</li> </ol> </div> </div> </div> <br />But in one case I had a little more complex scenario. I need to load all action items (and their content) of specified event. Some action items are composite and depends on other action items. So to prevent N+1 problem fetching composite action item’s dependencies I have to join action items table with itself on DependsOn field. <br /><a href="http://lh3.ggpht.com/-VD6-stc7nGY/TjcUBZDOLOI/AAAAAAAAAHM/ZyUTOzm_pJI/s1600-h/cd1%25255B6%25255D.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="cd1" border="0" alt="cd1" src="http://lh5.ggpht.com/-_mLKgAGGfqg/TjcUByMOsxI/AAAAAAAAAHQ/RJe58kS0jW8/cd1_thumb%25255B4%25255D.jpg?imgmax=800" width="332" height="309" /></a> <br />With an old LINQ it works fine: <br /> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:89b16821-19d1-476f-a40d-721e511ed85c" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #fff; max-height: 500px; overflow: auto"> <ol style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">var</span> query = session.Linq<<span style="color:#2b91af">ActionItem</span>>();</li> <li style="background: #f3f3f3">query.Expand(<span style="color:#a31515">"Options"</span>);</li> <li>query.Expand(<span style="color:#a31515">"Options.Dependants"</span>);</li> <li style="background: #f3f3f3">query.Expand(<span style="color:#a31515">"DependsOn"</span>);</li> <li><span style="color:#0000ff">var</span> actions = query.Where(a => a.Event.ID == eventID).ToList();</li> </ol> </div> </div> </div> <br />But this is impossible (or I did not achieved how to do it) with a new LINQ and QueryOver. <br />So I forced to use an old and good IQriteria: <br /> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:1fa16cee-d36a-4b53-825b-5cf8d5d26fae" class="wlWriterEditableSmartContent"> <div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"> <div style="background: #fff; max-height: 500px; overflow: auto"> <ol style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"> <li><span style="color:#0000ff">var</span> actions = session.CreateCriteria<<span style="color:#2b91af">ActionItem</span>>()</li> <li style="background: #f3f3f3"> .Add(<span style="color:#2b91af">Restrictions</span>.Eq(<span style="color:#a31515">"Event.ID"</span>, eventID))</li> <li> .SetFetchMode(<span style="color:#a31515">"Options"</span>, <span style="color:#2b91af">FetchMode</span>.Eager)</li> <li style="background: #f3f3f3"> .SetFetchMode(<span style="color:#a31515">"Options.Dependants"</span>, <span style="color:#2b91af">FetchMode</span>.Eager)</li> <li> .SetFetchMode(<span style="color:#a31515">"DependsOn"</span>, <span style="color:#2b91af">FetchMode</span>.Eager)</li> <li style="background: #f3f3f3"> .SetResultTransformer(<span style="color:#0000ff">new</span> <span style="color:#2b91af">DistinctRootEntityResultTransformer</span>())</li> <li> .List<<span style="color:#2b91af">ActionItem</span>>();</li> </ol> </div> </div> </div> </div> </div> Anonymoushttp://www.blogger.com/profile/17251669264955861104noreply@blogger.com0