tag:blogger.com,1999:blog-14820775455217245762024-03-13T08:14:54.279+01:00Gabriel's point of viewgschenkerhttp://www.blogger.com/profile/02864298954911764570noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-1482077545521724576.post-69203945754495111672007-06-22T17:02:00.001+02:002007-06-22T17:21:50.982+02:00How to use CSLA objects with NHibernate<p>Instead of using the ADO.NET data reader as in the reference implementation to fill a CSLA object with data one can as well use an O/R mapper tool like NHibernate and fetch the data through this object layer. </p><p>We have the following diagram</p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHLNi3H8fLZ0yyoGQXWd7zWq9Rm2gnL13ZvdRQjajEtVQ64scwQNidZtJ3OJRKwacUDOwjoJabTGjemOVgWdtRU2LfL4ceElJWViL7H4HCJkMgz9QCYrptwPyrvB_hh4McHD47tCjpG0I/s1600-h/ClassDiagram1.png"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjeR8uWDSH_yzrUFpjDks8e1KUPCgyRsobk_2b0nOM1BFedbGfuR4UeFEjqvGRNc1xJojQ9ppDiIXuN35lvGpnxrrNPGNuXfWgDbX87I5GaEyzyx-9D2jYHB0OaCj-6BuuWfIJu__Vptc/s1600-h/ClassDiagram1.png"><img id="BLOGGER_PHOTO_ID_5078906240185342930" style="CURSOR: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjeR8uWDSH_yzrUFpjDks8e1KUPCgyRsobk_2b0nOM1BFedbGfuR4UeFEjqvGRNc1xJojQ9ppDiIXuN35lvGpnxrrNPGNuXfWgDbX87I5GaEyzyx-9D2jYHB0OaCj-6BuuWfIJu__Vptc/s400/ClassDiagram1.png" border="0" /></a><br /><p></p><p>where <strong>Category</strong>, <strong>Product</strong> and <strong>ProductNote</strong> are the NHibernate data objects and <strong>ProductBO</strong>, <strong>ProductNotesBO</strong> and <strong>ProductNoteBO</strong> are the CSLA business objects.</p><h3>The root CSLA object ProductBO</h3><p>Typicall code might look as follows:</p><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private void DataPortal_Fetch(Criteria criteria)<br />{<br /> using (ISession session = SessionFactory.Current.OpenSession())<br /> {<br /> Product item = session.Get<Product>(criteria.ProductId);<br /> _productId = item.ProductID;<br /> _version = item.Version;<br /> _productName = item.ProductName;<br /> _categoryId = item.Category.CategoryID; </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //******** Get Child Collection(s)<br /> _notes = ProductNotesBO.GetProductNotesBO(item.Notes);<br /> }<br />}</span><br /><br /><p>On the other hand we also have to add or update the data in the database. Code might look as follows<br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">[Transactional(TransactionalTypes.TransactionScope)]<br />protected override void DataPortal_Insert()<br />{<br /> InsertOrUpdate();<br />} </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">[Transactional(TransactionalTypes.TransactionScope)]<br />protected override void DataPortal_Update()<br />{<br /> InsertOrUpdate();<br />}</span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private void InsertOrUpdate()<br />{<br /> using (ISession session = SessionFactory.Current.OpenSession())<br /> {<br /> Product item = new Product();<br /> item.ProductID = _productId;<br /> item.Version = _version;<br /> item.ProductName = _productName; </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //***************** This is how to solve Lookup-Type relations<br /> // (Category is a Lookup Table for Product related tasks)<br /> item.Category = new Category();<br /> item.Category.CategoryID = _categoryId;<br /> item.Category.Version = 999; </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //***************** Only update the item if needed (new or dirty)!<br /> if (base.IsDirty)<br /> {<br /> session.SaveOrUpdate(item); </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> if (IsNew)<br /> {<br /> _productId = item.ProductID; // get new (generated) ID!<br /> _version = item.Version; // and new Version number<br /> }<br /> MarkOld();<br /> } </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //***************** Update Child Collection(s)<br /> _notes.Update(session, item);<br /> session.Flush();<br /> }<br />}</span><br /><br /><p>To delete an object from the database one might use code as follows<br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">[Transactional(TransactionalTypes.TransactionScope)]<br />protected override void DataPortal_DeleteSelf()<br />{<br /> DataPortal_Delete(new Criteria(_productId));<br /> MarkNew();<br />} </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">[Transactional(TransactionalTypes.TransactionScope)]<br />private void DataPortal_Delete(Criteria criteria)<br />{<br /> using (ISession session = SessionFactory.Current.OpenSession())<br /> {<br /> //*************** First delete children (if allowed!!!)<br /> session.Delete("from ProductNote n where n.Product.ProductID=:id",<br /> criteria.ProductId, NHibernateUtil.Int32); </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //*************** And now delete the item itself!<br /> session.Delete("from Product p where p.ProductID = :id",<br /> criteria.ProductId, NHibernateUtil.Int32); </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> session.Flush();<br /> }<br />}</span><br /><br /><p>Note that we are using the <strong>Transactional</strong> attribute to make the insert, update and delete operations atomic.</p><h3>The CSLA child collection ProductNotesBO</h3><p>The factory methods of the child collection</p><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">public static ProductNotesBO NewProductNotesBO()<br />{<br /> return new ProductNotesBO();<br />} </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">public static ProductNotesBO GetProductNotesBO(<br /> IEnumerable<productnote>; list)<br />{<br /> return new ProductNotesBO(list);<br />} </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private ProductNotesBO()<br />{<br /> MarkAsChild();<br />} </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private ProductNotesBO(IEnumerable<productnote> list)<br />{<br /> Fetch(list);<br /> MarkAsChild();<br />}</span> </p><p>Code used to fetch data</p><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private void Fetch(IEnumerable<productnote> list)<br />{<br /> RaiseListChangedEvents = false; </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> foreach (ProductNote item in list)<br /> {<br /> Add(ProductNoteBO.GetProductNoteBO(item));<br /> } </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> RaiseListChangedEvents = true;<br />}</span><br /><br /><p>Code used to add, update and delete data</p><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">internal void Update(ISession session, Product parent)<br />{<br /> RaiseListChangedEvents = false; </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //------------------- Delete Removed Children ---------------------<br /> if (DeletedList.Count > 0)<br /> {<br /> StringBuilder ids = new StringBuilder();<br /> foreach (ProductNoteBO item in DeletedList)<br /> {<br /> if (ids.Length > 0) ids.Append(",");<br /> ids.Append(item.ProductNoteId);<br /> }<br /> string sql = string.Format(<br /> "from ProductNote n where n.ProductNoteID in ({0})",<br /> ids);<br /> session.Delete(sql); </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> DeletedList.Clear();<br /> } </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> //------------------- Add or Update Children ----------------------<br /> foreach (ProductNoteBO item in this)<br /> if (item.IsNew)<br /> item.Insert(session, parent);<br /> else<br /> item.Update(session, parent); </span><br /><br /><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> RaiseListChangedEvents = true;<br />}</span><br /><br /><h3>The CSLA child object ProductNoteBO</h3><p>The factory methods of the child business object<br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"></span></p><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">public static ProductNoteBO NewProductNoteBO(bool isChild)<br />{<br /> return new ProductNoteBO(isChild);<br />} </span><br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;">public static ProductNoteBO GetProductNoteBO(ProductNote item)<br />{<br /> return new ProductNoteBO(item);<br />} </span><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"><br />public static ProductNoteBO GetProductNoteBO(int productNoteId)<br />{<br /> return DataPortal.Fetch<productnotebo>(new Criteria(productNoteId));<br />} </span><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"><br />public static void DeleteProductNoteBO(int productNoteId)<br />{<br /> DataPortal.Delete(new Criteria(productNoteId));<br />} </span><br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private ProductNoteBO()<br />{ } </span><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"><br />private ProductNoteBO(bool isChild)<br />{<br /> if(isChild) MarkAsChild();<br />} </span><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"><br />private ProductNoteBO(ProductNote item)<br />{<br /> Fetch(item);<br /> MarkAsChild();<br />}</span><br /><br />Here we have introduced a <strong>isChild</strong> parameter which gives us the possibility to use this business object either as child object or as root object.<br /><br />Code used to fetch data<br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private void Fetch(ProductNote item)<br />{<br /> _productNoteId = item.ProductNoteID;<br /> _version = item.Version;<br /> _productNoteText = item.ProductNoteText;<br /> MarkOld();<br />}</span><br /><br />Code used to add and update data<br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"><br />internal void Insert(ISession session, Product parent)<br />{<br /> InsertOrUpdate(parent, session);<br />} </span><br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;">internal void Update(ISession session, Product parent)<br />{<br /> InsertOrUpdate(parent, session);<br />} </span><br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;">private void InsertOrUpdate(Product parent, ISession session)<br />{<br /> if (base.IsDirty)<br /> {<br /> ProductNote item = new ProductNote();<br /> item.ProductNoteID = _productNoteId;<br /> item.Version = _version;<br /> item.ProductNoteText = _productNoteText;<br /> item.Product = parent; // set parent<br /> session.SaveOrUpdate(item); </span><br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> if (IsNew)<br /> {<br /> _productNoteId = item.ProductNoteID; // load generated ID!<br /> _version = item.Version;<br /> } </span><br /><br /><span style="font-family:Courier New;font-size:85%;color:#0000ff;"> MarkOld();<br /> }<br />}</span></p>gschenkerhttp://www.blogger.com/profile/02864298954911764570noreply@blogger.com196tag:blogger.com,1999:blog-1482077545521724576.post-3115627202477357342007-06-21T10:37:00.001+02:002007-06-21T10:55:10.536+02:00Optimize NHibernate Queries<p>Some times I want to load an instance of an object which has one or several child collections. Usually I design my object relational mapping to use lazy loading by default. The result of this is that when loading a single instance of a object and accessing its child collections NHibernate spits out at least one additional query per collection. So I have many roudtrips to the server.</p><p>Fortuately NHibernate 1.2 offers the new possbility to create a "Multi-Query". The result is (at least for the SQL Server) that only ONE single roundtrip is made to the server and several resultsets are returned.</p><p>Let's make an example. We have a Category entity which has two child collections of type Product and Note. That is, any category object can have a list of associated Products and Notes. If I want to display all details of a specific Category on a view, then I have to load the details of the category object and the details of any of the associated products and notes objects. I have at least 3 queries to send to the database.</p><p>Now with the following syntax we reduce the roundtrips to the database needed to exactly one:</p><p><span style="font-family:Courier New;font-size:85%;color:#0000ff;">IList firstResultList = (IList) session.CreateMultiQuery()<br /> .Add("from Category cat left join fetch cat.Products where cat.CategoryID = :id")<br /> .Add("from Category cat left join fetch cat.Notes where cat.CategoryID = :id")<br /> .SetInt32("id", id)<br /> .List()[0];<br />Category item = (Category) firstResultList[0];</span> </p><div class="wlWriterSmartContent" id="0767317B-992E-4b12-91E0-4F059A8CECA8:0cada005-28a8-42af-9d9c-f475e455087a" contenteditable="false" style="PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-TOP: 0px">Technorati Tags: <a href="http://technorati.com/tags/.NET" rel="tag">.NET</a>, <a href="http://technorati.com/tags/NHibernate" rel="tag">NHibernate</a>, <a href="http://technorati.com/tags/C#" rel="tag">C#</a></div>gschenkerhttp://www.blogger.com/profile/02864298954911764570noreply@blogger.com77tag:blogger.com,1999:blog-1482077545521724576.post-55449289480007444862007-06-15T10:28:00.001+02:002007-06-21T11:01:12.508+02:00One-to-one mapping and Lazy loading<p>Often we have the following situation: An entity has some attributes that are important and often accessed and then it has some other attributes that are either rarely used or their content is large in size (e.g. a photo or a document). In such situations it is common to split the entity into two tables. One table containing the important attributes and the other the remaining ones. A typical example is table 'Person' and table 'PersonDetails'. These tables are relatet by a 1 to 0..1 relation. That is a person can have person details but doesn't need to. On the other hand 'person details' always belong to a 'person'.</p> <p>Question: How can we instruct NHibernate and/or ActiveRecord to give us such a relation. We want to have the possibility to load a list of persons WITHOUT loading also their corresponding details. The details should ONLY be loaded when we really access them. That is called 'Lazy Loading'.</p> <p>Just using a one-to-one relation doesn't work! We have to use a 'trick' and use a combination of a many-to-one and a one-to-one relation. This solves our problem. </p> <h3>NHibernate</h3> <p>Let us look at the code:</p> <p><font color="#0000ff">namespace NHibernateTest<br>{<br> public class Person<br> {<br> private int _personID;<br> private string _lastName;<br> private string _firstName;<br> private PersonPhoto _photo; </font> <p><font color="#0000ff"> public virtual int PersonID<br> {<br> get { return _personID; }<br> set { _personID = value; }<br> } </font> <p><font color="#0000ff"> public virtual PersonPhoto Photo<br> {<br> get { return _photo; }<br> set { _photo = value; }<br> } </font> <p><font color="#0000ff"> public virtual string LastName<br> {<br> get { return _lastName; }<br> set { _lastName = value; }<br> } </font> <p><font color="#0000ff"> public virtual string FirstName<br> {<br> get { return _firstName; }<br> set { _firstName = value; }<br> }<br> } </font> <p><font color="#0000ff"> public class PersonPhoto<br> {<br> private int _personID;<br> private byte[] _photo;<br> private Person _owner; </font> <p><font color="#0000ff"> public virtual int PersonID<br> {<br> get { return _personID; }<br> set { _personID = value; }<br> } </font> <p><font color="#0000ff"> public virtual Person Owner<br> {<br> get { return _owner; }<br> set { _owner = value; }<br> } </font> <p><font color="#0000ff"> public virtual byte[] Photo<br> {<br> get { return _photo; }<br> set { _photo = value; }<br> }<br> }<br>}</font> <p>and now at the NHibernate mapping file(s)</p> <p><font color="#0000ff"><?xml version="1.0" encoding="utf-8" ?><br><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTest" namespace="NHibernateTest"><br> <class name="Person" ><br> <id name="PersonID" type="Int32"><br> <generator class="identity" /><br> </id><br> <property name="LastName" type="String" length="50" /><br> <property name="FirstName" type="String" length="50" /><br> <many-to-one name="Photo" class="PersonPhoto" /> <br> </class> </font> <p><font color="#0000ff"> <class name="PersonPhoto"><br> <id name="PersonID" type="Int32"><br> <generator class="foreign"><br> <param name="property">Owner</param><br> </generator><br> </id><br> <property name="Photo" type="BinaryBlob" /><br> <one-to-one name="Owner" class="Person" constrained="true" /><br> </class><br></hibernate-mapping></font> <p><strong>Note: </strong></p> <ul> <li>on the "parent" side (Person) we have the many-to-one relation which points to PersonPhoto. <li>on the "child" side (PersonPhoto) the primary key (PersonID) is the same as on the "parent" side. Thus the value must be "inherited" from the parent. This is the reason to use "foreign" as generator class. The <param> tag just points to the Property from which NHibernate can get this PK value, in our case the property is called Owner (which is the Person who owns this photo). <li>on the "child" side we have the one-to-one relation which points to Person. <li>the one-to-one relation sets constrained=true since the person details belongs to a person (a person MUST exists).</li></ul> <h3>ActiveRecord</h3> <p>We can define the same behaviour in ActiveRecord. Here I choose a similar sample as above, a one-to-one relation between a Car and its CarPhoto. Code explains better than many words, thus:</p> <p><font color="#0000ff">[ActiveRecord("Car", Lazy = true)]<br>public class Car : ActiveRecordBase<Car><br>{<br> private Guid _CarID;<br> private CarPhoto _photo;<br> private string _make; </font> <p><font color="#0000ff"> [PrimaryKey(PrimaryKeyType.Guid, "CarID", ColumnType = "Guid")]<br> public virtual Guid CarID<br> {<br> get { return _CarID; }<br> set { _CarID = value; }<br> } </font> <p><font color="#0000ff"> [BelongsTo(Column = "CarID", Unique = true)]<br> public virtual CarPhoto Photo<br> {<br> get { return _photo; }<br> set { _photo = value; }<br> } </font> <p><font color="#0000ff"> [Property(ColumnType = "String", Length = 50)]<br> public virtual string Make<br> {<br> get { return _make; }<br> set { _make = value; }<br> }<br>} </font> <p><font color="#0000ff">[ActiveRecord("CarPhoto", Lazy = true)]<br>public class CarPhoto : ActiveRecordBase<CarPhoto><br>{<br> private Guid _CarID;<br> private Car _owner;<br> private byte[] _photo; </font> <p><font color="#0000ff"> [PrimaryKey(PrimaryKeyType.Foreign, "CarID", ColumnType = "Guid")]<br> public virtual Guid CarID<br> {<br> get { return _CarID; }<br> set { _CarID = value; }<br> } </font> <p><font color="#0000ff"> [OneToOne(Constrained = true)]<br> public virtual Car Owner<br> {<br> get { return _owner; }<br> set { _owner = value; }<br> } </font> <p><font color="#0000ff"> [Property(ColumnType = "BinaryBlob", SqlType = "VARBINARY(MAX)")]<br> public virtual byte[] Photo<br> {<br> get { return _photo; }<br> set { _photo = value; }<br> }<br>}</font> <p>Now I can happily load a list of cars and the photos are not loaded by default but only when I really access them...</p>gschenkerhttp://www.blogger.com/profile/02864298954911764570noreply@blogger.com45tag:blogger.com,1999:blog-1482077545521724576.post-18380396230106761172007-06-08T16:17:00.000+02:002007-06-21T11:01:12.509+02:00Prequisites for Distributed Applications<p><span style="font-size: 85%; font-family: trebuchet ms">When developing any more or less complex LOB application the developer needs some decent patterns, frameworks and tools to efficiently fullfill the given task. I assemled a list of elements which I personally recommend </span> <ul> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%"><strong>Base Framework</strong>: .NET 2.0 or 3.0 </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%"><strong>O/R-Mapping</strong>: NHibernate and ActiveRecords </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%"><strong>IoC</strong>: Castle Windsor Container or MS ObjectBuilder </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%"><strong>Testing</strong>: NUnit, MbUnit, Rhino.Mocks </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%"><strong>Business Layer</strong>: CSLA </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%"><strong>Smart Client</strong>: CAB, SCSF</span></span></li></ul> <h3><span style="font-family: trebuchet ms">Tools</span><br></h3> <ul> <li><span style="font-size: 85%; font-family: trebuchet ms">VS 2005 Professional or Team Edition </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Resharper 2.5 or higher </span> <li><span style="font-size: 85%; font-family: trebuchet ms">ActiveWriter Plugin for VS </span> <li><span style="font-size: 85%; font-family: trebuchet ms">TestDriven Plugin for VS</span></li></ul> <h3><span style="font-family: trebuchet ms">Patterns</span></h3> <ul> <li><span style="font-size: 85%; font-family: trebuchet ms">Presentation Layer </span><span style="font-family: trebuchet ms"></span> <ul> <li><span style="font-size: 85%; font-family: trebuchet ms">MVC: Model View Controller, or </span> <li><span style="font-size: 85%; font-family: trebuchet ms">MVP: Model View Presenter</span></li></ul></li></ul> <h3><span style="font-family: trebuchet ms">Processes/Design</span></h3> <ul> <li><span style="font-size: 85%; font-family: trebuchet ms">Domain Driven Design (DDD) </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Test Driven Development (TDD) </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Behaviour Driven Development (BDD)</span></li></ul> <p><span style="font-size: 85%; font-family: trebuchet ms">All the items mentioned above need some further discussion and will be covered in more details below and in my future posts.<br></span><br> <p><span style="font-size: 85%"></span> <p> <h3><font face="Trebuchet MS">Acronyms</font></h3> <p><font face="Trebuchet MS">First let me define the acronyms used so far:</font></p> <table cellspacing="0" cellpadding="2" width="402" border="0" unselectable="on"> <tbody> <tr></tr></tbody></table> <table cellspacing="0" cellpadding="2" width="400" border="0" unselectable="on"> <tbody> <tr> <td valign="top" width="136"><span style="font-size: 85%"><strong>Acronym</strong></span></td> <td valign="top" width="262"><span style="font-size: 85%"><strong>Description</strong></span></td></tr> <tr> <td valign="top" width="136"><span style="font-size: 85%">O/R-Mapping</span></td> <td valign="top" width="262"><span style="font-size: 85%">Object-Relational Mapping. A technique used to bridge the gap between the relational database and the object oriented application</span></td></tr> <tr> <td valign="top" width="136"><span style="font-size: 85%">IoC</span></td> <td valign="top" width="262"><span style="font-size: 85%">Inversion of Control: A technique used to instanciate, instrument and maintain objects during their life time. Especially helpful if one is developing loosely coupled applications</span> </td></tr> <tr> <td valign="top" width="136"><span style="font-size: 85%">Unit Test<br></span></td> <td valign="top" width="262"><span style="font-size: 85%">A test methodology used to test the state and behaviour of a single unit (e.g. object) </span></td></tr> <tr> <td valign="top" width="136"><span style="font-size: 85%">CSLA</span></td> <td valign="top" width="262"><span style="font-size: 85%">Componentized Scalable Logical Architecture. Rockford Lhotka’s CSLA .NET framework is an application development framework that helps build a powerful, maintainable business logic layer for Windows, Web and Web Services applications </span></td></tr> <tr> <td valign="top" width="136">MVC</td> <td valign="top" width="262"><span style="font-size: 85%">Model View Controller Pattern </span></td></tr> <tr> <td valign="top" width="136">MVP</td> <td valign="top" width="262"><span style="font-size: 85%">Model View Presenter Pattern </span></td></tr> <tr> <td valign="top" width="136">DDD</td> <td valign="top" width="262"><span style="font-size: 85%">Domain Driven Design</span> </td></tr> <tr> <td valign="top" width="136">BDD</td> <td valign="top" width="262"><span style="font-size: 85%">Behaviour Driven Design </span></td></tr> <tr> <td valign="top" width="136">TDD</td> <td valign="top" width="262"><span style="font-size: 85%">Test Driven Developement</span> </td></tr> <tr> <td valign="top" width="136">CAB</td> <td valign="top" width="262"><span style="font-size: 85%">Componentized (User Interface) Application Block</span> </td></tr> <tr> <td valign="top" width="136">SCSF</td> <td valign="top" width="262"><span style="font-size: 85%">Smart Client Software Factory</span> </td></tr> <tr> <td valign="top" width="136">LOB</td> <td valign="top" width="262"><span style="font-size: 85%">Line of Business (Applications)</span></td></tr></tbody></table> <p><span style="font-family: trebuchet ms"><strong>Links, Downloads</strong></span> </p> <ul> <li><span style="font-size: 85%; font-family: trebuchet ms">The </span><a href="http://www.nhibernate.org/"><span style="font-size: 85%; font-family: trebuchet ms">NHiberante</span></a><span style="font-size: 85%; font-family: trebuchet ms"> Project </span> <li><span style="font-size: 85%; font-family: trebuchet ms">The </span><a href="http://www.castleproject.org/"><span style="font-size: 85%; font-family: trebuchet ms">Castle</span></a><span style="font-size: 85%; font-family: trebuchet ms"> Project for <strong>Active Records</strong> and <strong>Windsor Container</strong> </span> <li><span style="font-size: 85%; font-family: trebuchet ms">The </span><a href="http://www.codeplex.com/ObjectBuilder"><span style="font-size: 85%; font-family: trebuchet ms">MS ObjectBuilder</span></a><span style="font-size: 85%; font-family: trebuchet ms"> Dependency Injection Framework </span> <li><span style="font-size: 85%; font-family: trebuchet ms">The </span><a href="http://forums.lhotka.net/"><span style="font-size: 85%; font-family: trebuchet ms">CSLA .NET</span></a><span style="font-size: 85%; font-family: trebuchet ms"> Project of Rockford Lhotka </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Testing with </span><a href="http://www.nunit.org/"><span style="font-size: 85%; font-family: trebuchet ms">NUnit</span></a><span style="font-size: 85%; font-family: trebuchet ms">, </span><a href="http://www.mbunit.com/"><span style="font-size: 85%; font-family: trebuchet ms">MbUnit</span></a><span style="font-size: 85%; font-family: trebuchet ms">, </span><a href="http://www.ayende.com/projects/rhino-mocks.aspx"><span style="font-size: 85%; font-family: trebuchet ms">Rhino.Mocks</span></a><span style="font-size: 85%; font-family: trebuchet ms"> and the </span><a href="http://www.testdriven.net/"><span style="font-size: 85%; font-family: trebuchet ms">TestDriven</span></a><span style="font-size: 85%; font-family: trebuchet ms"> AddIn for Visual Studio </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Refactoring and more with </span><a href="http://www.jetbrains.com/resharper"><span style="font-size: 85%; font-family: trebuchet ms">ReSharper</span></a><span style="font-size: 85%; font-family: trebuchet ms"> </span> <li><a href="http://altinoren.com/activewriter/"><span style="font-size: 85%; font-family: trebuchet ms">ActiveWriter</span></a><span style="font-size: 85%; font-family: trebuchet ms"> AddIn for Visual Studio </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Smart Client Developement with MS </span><a href="http://www.codeplex.com/smartclient"><span style="font-size: 85%; font-family: trebuchet ms">CAB and SCSF</span></a><span style="font-size: 85%; font-family: trebuchet ms"> </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Test-Driven Development - </span><a href="http://www.testdriven.com/"><span style="font-size: 85%; font-family: trebuchet ms">TDD</span></a><span style="font-size: 85%; font-family: trebuchet ms"> </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Domain-Driven Design - </span><a href="http://www.domaindrivendesign.org/"><span style="font-size: 85%; font-family: trebuchet ms">DDD</span></a><span style="font-size: 85%; font-family: trebuchet ms"> </span> <li><span style="font-size: 85%; font-family: trebuchet ms">Behaviour-Driven Development - </span><a href="http://behaviour-driven.org/"><span style="font-size: 85%; font-family: trebuchet ms">BDD</span></a></li></ul>gschenkerhttp://www.blogger.com/profile/02864298954911764570noreply@blogger.com8tag:blogger.com,1999:blog-1482077545521724576.post-87038895789243682332007-06-08T15:43:00.000+02:002007-06-21T11:01:12.509+02:00O/R Mapping<span style="font-size: 85%; font-family: trebuchet ms">To bridge the gap between the relational database system (RDBMS) and the object oriented application domain we choose to use </span><a href="http://www.nhibernate.org/"><span style="font-size: 85%; font-family: trebuchet ms">NHibernate</span></a><span style="font-size: 85%; font-family: trebuchet ms">. NHibernate allows us to define mappings between objects and their corresponding tables in the database via xml mapping files. Not only can one define the mappings between objects and tables but also the relations between different objects can be mapped to the corresponding relations in the database. NHibernate supports 1 to 1, 1 to many and many to many relations. These are the most common scenarios we typically encounter in LOB.<br>When we use a Domain-Driven Design (DDD) NHibernate supports us with the possibility to automatically generate the necessary database schema. Developing the object model first and then derive the database schema from the object model is in our opinion a more "natural" way of implementing a "green field" application than the more "traditional" way of implementing an application where the Entity Relationship Diagram (ERD) is designed first.<br>When using NHibernate one immediately is looking for a way to avoid the tedious task to manually write the xml-mapping files for each object in the domain. Fortunately the Castle Project has </span><a href="http://www.castleproject.org/activerecord/"><span style="font-size: 85%; font-family: trebuchet ms">ActiveRecord</span></a><span style="font-size: 85%; font-family: trebuchet ms"> as one of its sub-projects. ActiveRecords allows us to decorate the classes in our domain directly with Attributes instead of writing xml-mapping files. ActiveRecord is well documented and I do not want to repeat this documentation here. But I want to discuss a concrete example.<br>But wait! Do I really have to write my classes by hand and decorate them and its respective properties with Attibutes? Isn't there a "better" way of doing it? Yes, indeed there is: Gökhan Altinören has written a VS PlugIn which allows us to visually desing our object model. Its the </span><a href="http://altinoren.com/activewriter/"><span style="font-size: 85%; font-family: trebuchet ms">ActiveWriter</span></a><span style="font-family: trebuchet ms"><span style="font-size: 85%"> PlugIn which I'll be using in the following example.<br></span>Example</span><br> <ul> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%">A person has hobbies. The relation between a person and a hobby is many-to-many since a person can have many hobbies and a single hobby like swimming can be exercised by many different persons.</span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%">A person has assigned tasks. The relation between a person and a task is also many-to-many since a person can have many assigned tasks and a single task like "write a blog entry on topic xyz..." can be assigned to many different persons. </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%">A person can blog - as I do here. A person can maintain several blogs but each blog belongs to a single person (at least in my sample). Thus the relation between person and blog is one-to-many. </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%">To a person we want to be able to store a photo. Since a photo can be rather large we decide NOT to store the photo directly in the Person object but create an extra PersonPhoto object which is owned by the Person object. So as a benefit we have the possibility to only load the PersonPhoto data if really needed. The relation between a person and a photo is one-to-one. </span></span> <li><span style="font-family: trebuchet ms"><span style="font-size: 85%">A person has an address. But also e.g. a company has an address. So we decide to not make the relation between person and address as one-to-one but rather many-to-one.But the relation has a further restriction in so far that the "many" part of the relation is effectively a unique restriction since a single address cannot (in reality) be shared among different persons (or e.g. companies). </span></span><span style="font-family: trebuchet ms"><span style="font-size: 85%"></li></ul></span></span><span style="font-size: 85%"> <p>This leads us to the following design (in ActiveWriter)<br></span></p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglebZn_xW8d_ybpE7qhJBd79vnuf_ZZSnP6e4AVVvbXRHNoYnDRyahMlMoQNLRLwMlKgQw3tWx4ZEeYYVSAJVoJ8-qU07ZnYFAjCIrPMU8dPqOfh2yIgZE4yFuG5muzOQMyp3ObHNRSzc/s1600-h/Model.jpg"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXHCRyIduoTMQAHNIvjU_IrIVOHGDUWYaL3Q0DaQAh49XW3-AO_ZBYoYKZLK_A-T0p1HrsU0_UVu9DUjA0ZMW20LwIpthN6jcxEYdvjnPN8pJyToHnk_lY-iAePF-KcKeUREpwtIYH2-M/s1600-h/Model.jpg"><img id="BLOGGER_PHOTO_ID_5073690955887090434" style="cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXHCRyIduoTMQAHNIvjU_IrIVOHGDUWYaL3Q0DaQAh49XW3-AO_ZBYoYKZLK_A-T0p1HrsU0_UVu9DUjA0ZMW20LwIpthN6jcxEYdvjnPN8pJyToHnk_lY-iAePF-KcKeUREpwtIYH2-M/s400/Model.jpg" border="0"></a><br>Classes<br><span style="font-size: 85%">For each class we have to define the mapping via the property window. Just select the corresponding class and modify the atributes similar to the example below<br></span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZHvGcUBOtF7wD5NAzFtn_hzsPrQN3rzfpBcTnPBiaLOqW5WfUm6UVj72VAMi9QfE6ISjZ2oQ3pe70SwkG5UZ2o2K5-ggEjoYdNXXzOrZQhjdXxIza6w7EcGoVWanbKNhvuMg2P56512s/s1600-h/ClassAttributes.jpg"><img id="BLOGGER_PHOTO_ID_5073691535707675410" style="cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZHvGcUBOtF7wD5NAzFtn_hzsPrQN3rzfpBcTnPBiaLOqW5WfUm6UVj72VAMi9QfE6ISjZ2oQ3pe70SwkG5UZ2o2K5-ggEjoYdNXXzOrZQhjdXxIza6w7EcGoVWanbKNhvuMg2P56512s/s400/ClassAttributes.jpg" border="0"></a><br><span style="font-size: 85%">In the above example the mapping is between the <strong>Person</strong> class and a table also called <strong>Person</strong> which is defined in the (database) schema gns.<br>Note that when not defining the Table attribute NHibernate automatically takes the value of the attribute Name as the name for the underlying table.<br></span>Properties<br><span style="font-size: 85%">Note that each object (or class) has a property Key. This is a value which uniquely identifies an instance of the respective type. The Key property is mapped to the primary key column in the underlying database table.<br>To make our application multi-user friendly I also introduced a Version property for each object. This allows us to handle any concurrent (write) access to a specific object. NHibernate offers built-in functionality for such properties.<br>The other properties are common properties and are all of type string except for the Photo property in the PersonPhoto class which is of type BinaryBlob.<br>Each Property of a class can be configured through the Properties Windows. Just activate the corresponding property in the ActiveWriter designer.<br>For the Version property I have set the following values<br><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6Tjmaa4Dj7G-StvJkzPGmgZGHz3e0E9bBupfPK8fnnfyMjtUAqo3RbYUkHMaNQ2wDCxulGIJVXFDK3b0WE2or2YhP-Wl_Hs7b8KZykw2_gzG4xjrdU_whp0oZjfAThJlnTd4Inmhm928/s1600-h/Version.jpg"><img id="BLOGGER_PHOTO_ID_5073691668851661602" style="cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6Tjmaa4Dj7G-StvJkzPGmgZGHz3e0E9bBupfPK8fnnfyMjtUAqo3RbYUkHMaNQ2wDCxulGIJVXFDK3b0WE2or2YhP-Wl_Hs7b8KZykw2_gzG4xjrdU_whp0oZjfAThJlnTd4Inmhm928/s400/Version.jpg" border="0"></a><br>For the Key Property of the Person object I have set the following values. Note that I use Guid's for the key. One can as well use int or long.<br><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPNoeozsv9VfcBSKUvK2S2eDtEv6MECGrU_vIr38tP3ZvyMWfb79yuxOMTxvJTEoD1L66kp2k6lgUpW4kvsHmZ1fe80mVsO63qruBloQOlAIQl7U3sQ_SDJT14y45-XoaU4t3G4v51F44/s1600-h/PrimaryKey.jpg"><img id="BLOGGER_PHOTO_ID_5073692781248191346" style="cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPNoeozsv9VfcBSKUvK2S2eDtEv6MECGrU_vIr38tP3ZvyMWfb79yuxOMTxvJTEoD1L66kp2k6lgUpW4kvsHmZ1fe80mVsO63qruBloQOlAIQl7U3sQ_SDJT14y45-XoaU4t3G4v51F44/s400/PrimaryKey.jpg" border="0"></a><br>In the Column attribute you define how the corresponding column will be called in the underlying table Person. If you don't specify a value then NHibernate will automatically take the value of the attribute Name as the column name. This fact was used for the Version property defined above.<br>The other properties are easy and I'll show here as an example the property Photo of the PersonPhoto class<br></span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjSl8Df1k1LJlcfTeVCWZvl02_FpKBMbjkizyehml9Wa-5c9Y9tNLfyCwM3yh0CBybSYJX53hp_DngBnydxV7MvM6p1X4hWL_jWNIIancJHOOIlfVkVH_fkvazEy8VN85nKhgKz4yTtXs/s1600-h/Normal+Property.jpg"><img id="BLOGGER_PHOTO_ID_5073692592269630274" style="cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjSl8Df1k1LJlcfTeVCWZvl02_FpKBMbjkizyehml9Wa-5c9Y9tNLfyCwM3yh0CBybSYJX53hp_DngBnydxV7MvM6p1X4hWL_jWNIIancJHOOIlfVkVH_fkvazEy8VN85nKhgKz4yTtXs/s400/Normal+Property.jpg" border="0"></a><br>Relations<br><span style="font-size: 85%">The most interesting part are the relations among the different classes (or objects). The first time you use ActiveWriter you might be a little bit confused about the naming convention. The author of ActiveWriter is working on it and will soon provide a detailed description. Never the less let's have a look at the various relation types<br><span style="font-size: 100%">One-to-One relation<br></span>Let's look at the one-to-one relation between Person and PersonPhoto. I have defined the following attributes<br><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq0Fa-IYpZ7qiLlzbOuaTJNJs9rpWEKPOOOfx6YF-sBVrDy1T2NK2qY3g3c0dNWrI9k2Z9HGIYo7SPHBJfQo4eDVNumiBc4TFtNvLPDstkdH1woK-ArkKerC1aDJvIxxY27jwzN8eb41k/s1600-h/one-to-one.jpg"><img id="BLOGGER_PHOTO_ID_5073692725413616482" style="cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq0Fa-IYpZ7qiLlzbOuaTJNJs9rpWEKPOOOfx6YF-sBVrDy1T2NK2qY3g3c0dNWrI9k2Z9HGIYo7SPHBJfQo4eDVNumiBc4TFtNvLPDstkdH1woK-ArkKerC1aDJvIxxY27jwzN8eb41k/s400/one-to-one.jpg" border="0"></a><br>What does this mean? Source Constrained = True means that a photo cannot exist without a corresponding person but vice versa a person can exist without having a photo (Target Constrained = False).Target Cascade = All means that when saving or deleting a person the owned photo is automatically save or deleted too. On the other hand when I save or delete a photo the corresponding person object is not affected (Source Cascade = None).<br><span style="font-size: 100%">One-to-Many relation<br></span>As an example let's have a look at the relation between Person and Blog(s).<br><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFTCzRX5O0kFQxRpx6ASGZ3-fj1VJe__doJvRFn89-OvVbXSitv8Zhkf7WsZMalWyfnJ2RrAF3NyXIZpd9h8cP74xR4mf75IIvRmNSpZzPLuztyaaxfhopGwEJEbcpp9cxNi6IHQJmHZg/s1600-h/one-to-many.jpg"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6ziwk-PQrnB2fP_rnVa4LEQAPBd9jOGGSTfp9eZaXeVheW4TycrIyOzJB15B4goETDxh2-NPZRE_6WTJsH_ypGposyJ5l1qq8OhPVtCXBM9cZxMxiFoLM5BVvIeaPwiaRmYSuD1kShik/s1600-h/one-to-many.jpg"><img id="BLOGGER_PHOTO_ID_5073695607336672162" style="float: left; margin: 0px 10px 10px 0px; cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6ziwk-PQrnB2fP_rnVa4LEQAPBd9jOGGSTfp9eZaXeVheW4TycrIyOzJB15B4goETDxh2-NPZRE_6WTJsH_ypGposyJ5l1qq8OhPVtCXBM9cZxMxiFoLM5BVvIeaPwiaRmYSuD1kShik/s320/one-to-many.jpg" border="0"></a><br>In this example consider the "Source..." as the One-side (here the Person) and the "Target..." as the Many-side (here the Blog) of the relation.<br>Note:<br>the Target Lazy = True setting which means that I do not want to have all blogs automatically loaded when I load a person object. Only if I access the person's blog(s) NHibernate shall load the corresponding blog(s). The Property Blogs in the Person class is of type IList<blog>. This list is sorted by BlogName (see the Target Order By = BlogName)</span> <p><span style="font-size: 85%">.</span></p> <p><span style="font-size: 85%">.</span></p> <p><span style="font-size: 85%">.</span></p> <p><span style="font-size: 85%">.</span></p> <p></p> <p><span style="font-size: 85%"><span style="font-size: 100%"></span></span></p> <p><span style="font-size: 85%"><span style="font-size: 100%"></span></span></p> <p><span style="font-size: 85%"><span style="font-size: 100%"></span></span></p> <p><span style="font-size: 85%"><span style="font-size: 100%"></span></span></p> <p><span style="font-size: 85%"><span style="font-size: 100%"></span></span></p> <p><span style="font-size: 85%"><span style="font-size: 100%">Many-to-Many relation<br></span>Here we look at the relation between the Person and Task classes.<br><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-lCWiukqzhi_0X9JPzIBQt33qfpmPisoe0fPD82eaGWp2BlcjVcWRiuayt6l_jaPpt1eFA8ozcxPeRPSxCcFv_06UdoZXUcAxWHsTdJiwTCll7gqn3EfDfYRnGI38Y78WH-NNsxr6_0Y/s1600-h/many-to-many.jpg"><img id="BLOGGER_PHOTO_ID_5073694933026806674" style="float: left; margin: 0px 10px 10px 0px; cursor: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-lCWiukqzhi_0X9JPzIBQt33qfpmPisoe0fPD82eaGWp2BlcjVcWRiuayt6l_jaPpt1eFA8ozcxPeRPSxCcFv_06UdoZXUcAxWHsTdJiwTCll7gqn3EfDfYRnGI38Y78WH-NNsxr6_0Y/s320/many-to-many.jpg" border="0"></a><br>Any many-to-many relation needs a link table in the database. Here we define the link table to be named PersonTask and residing in the schema gns.The setting Source Lazy = True means that I do not want all tasks to be automatically loaded when I load a person. They should only be loaded when I want to access them.The other settings are more or less self-describing.</span></p><br> <p><span style="font-size: 85%"></span></p><br> <p><span style="font-size: 85%"></span></p><br> <p><span style="font-size: 85%"></span></p><br> <p><span style="font-size: 85%"></span></p><br> <p><span style="font-size: 85%"></span></p><br> <p><span style="font-size: 85%"></span></p><br> <p><span style="font-size: 85%"></span></p> <p><span style="font-size: 85%"></span></p> <p><span style="font-size: 85%"></span></p> <p><span style="font-size: 85%"></span></p> <p><span style="font-size: 85%">.</span></p> <p><span style="font-size: 85%">to be continued...<br></p></span></span></span>gschenkerhttp://www.blogger.com/profile/02864298954911764570noreply@blogger.com241