<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3702639791878600134</id><updated>2011-07-07T23:43:12.513-07:00</updated><category term='NHibernate'/><category term='Data Structure'/><category term='Desktop'/><category term='SQL'/><category term='Program Architecture'/><category term='4 Table'/><category term='Separation of Concerns'/><category term='.Net'/><title type='text'>A New Development</title><subtitle type='html'>My boring blog wherein I discuss software development.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tomdietrich.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://tomdietrich.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Dietrich</name><uri>http://www.blogger.com/profile/15573313167900812535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3702639791878600134.post-6665318616798695418</id><published>2010-07-29T09:04:00.000-07:00</published><updated>2010-07-29T09:04:32.834-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Structure'/><category scheme='http://www.blogger.com/atom/ns#' term='4 Table'/><title type='text'>Querying the 4 table structure.</title><content type='html'>In my&amp;nbsp;&lt;a href="http://tomdietrich.blogspot.com/2010/07/bliss-and-four-table-structure.html"&gt;previous post&lt;/a&gt;, I described how four physical tables can be thought of as a means to create infinite virtual tables. One natural question you may have about this technique is "Ok, so how the heck do I query the virtual table?"&amp;nbsp;It may seem a little challenging at first, but it is more than possible. Easy even.&lt;br /&gt;&lt;br /&gt;Take our customer-process virtual table for example.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8AWt_3xqhwM/TEBdMWXC02I/AAAAAAAAB48/M_aH_L-DiEM/s1600/4TableStructure3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="117" src="http://2.bp.blogspot.com/_8AWt_3xqhwM/TEBdMWXC02I/AAAAAAAAB48/M_aH_L-DiEM/s400/4TableStructure3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;You need a query that will tell you every customer that has a max particle size over 1.5 inches. Remember that the table structure that drives this virtual table looks like this.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8AWt_3xqhwM/TEBa9FxsbJI/AAAAAAAAB40/wG8N5or8p80/s1600/4TableStructure2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_8AWt_3xqhwM/TEBa9FxsbJI/AAAAAAAAB40/wG8N5or8p80/s320/4TableStructure2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;What we'll want is all the customer-process data results where the value is &amp;gt; 1.5 and the process-info-detail is Cement-Mixing's Max Particle Size.&lt;br /&gt;&lt;br /&gt;That query simply looks like this :&lt;br /&gt;&lt;br /&gt;SELECT CPD.CustomerProcessID&lt;br /&gt;FROM Cust-Process-Data CPD&lt;br /&gt;INNER JOIN Process-Info-Detail PID ON CPD.ProcessInfoDetailID = PID.ProcessInfoDetailID&lt;br /&gt;INNER JOIN Process-Info PI ON PID.ProcessInfoID = PI.ProcessInfoID&lt;br /&gt;WHERE PI.Process = 'Cement Mixing' AND PID.ProcessInfo = 'Max Particle Size' AND CPD.Value &amp;gt; 1.5&lt;br /&gt;&lt;br /&gt;Or, to&amp;nbsp;genericise&amp;nbsp;it,&lt;br /&gt;&lt;br /&gt;SELECT RowHeaderID&lt;br /&gt;FROM CellData CD&lt;br /&gt;INNER JOIN ColumnHeader CH ON CD.ColumnID = CH.ColumnID&lt;br /&gt;INNER JOIN Table T ON CH.TableID = T.TableID&lt;br /&gt;WHERE T.TableName = '{Desired Table}' AND CH.ColumnName = '{Desired Column}' AND CD.Value {ValueClause}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What I'll typically do with this clause is throw it in a sub select and join against the result. Pretend the above SQL format is abbreviated as Query in the following examples.&lt;br /&gt;&lt;br /&gt;SELECT CustomerID&lt;br /&gt;FROM CustomerProcess CP&lt;br /&gt;INNER JOIN (Query) Q1 ON CP.CustomerProcessID = Q1.CustomerProcessID&lt;br /&gt;&lt;br /&gt;And BAM we've got our results. This query structure is flexible enough to mimic 'and' and 'or' clauses against the underlying virtual tables. To get an and, you simply need to inner join the different subselect queries- the result set will only include rows that meet all the provided criteria - like so.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;SELECT CustomerID&amp;nbsp;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;FROM CustomerProcess CP&amp;nbsp;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;INNER JOIN (Query) Q1 ON CP.CustomerProcessID = Q1.CustomerProcessID&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;INNER JOIN (Query2) Q2 ON Q1.CustomerProcessID = Q2.CustomerProcessID&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;And to mimic an 'Or' clause, you can simply union the sub selects. Cool, huh?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3702639791878600134-6665318616798695418?l=tomdietrich.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomdietrich.blogspot.com/feeds/6665318616798695418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/querying-4-table-structure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/6665318616798695418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/6665318616798695418'/><link rel='alternate' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/querying-4-table-structure.html' title='Querying the 4 table structure.'/><author><name>Dietrich</name><uri>http://www.blogger.com/profile/15573313167900812535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_8AWt_3xqhwM/TEBdMWXC02I/AAAAAAAAB48/M_aH_L-DiEM/s72-c/4TableStructure3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3702639791878600134.post-3365544609314688964</id><published>2010-07-21T06:54:00.000-07:00</published><updated>2010-07-21T06:54:21.825-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Separation of Concerns'/><title type='text'>IProvider to sidestep dependency problems.</title><content type='html'>This is another not-new concept, but it's one that I haven't found explained simply and might benefit some people.&lt;br /&gt;&lt;br /&gt;When you have a three tier structure like &lt;a href="http://tomdietrich.blogspot.com/2010/07/three-tier-structure-on-desktop.html"&gt;I've suggested&lt;/a&gt;, and you've got a process that requires looking though a large amount of data for a matching item, it may seem like you've got yourself in a pickle. Since the Data &amp;nbsp;assembly is&amp;nbsp;dependent&amp;nbsp;on the Core assembly, Core can not use Data directly. The first instinct may be to just relate all the Core objects and set up&amp;nbsp;mappings&amp;nbsp;to permit this data to be lazily loaded during the process by NHibernate. This &lt;i&gt;does&lt;/i&gt;&amp;nbsp;work, actually, but it has a few smells to it. First, Core is now being modified by our data concerns. Sometimes these relationships are appropriate from a purely business need, but many times they are not. Second, Data is now being modified by our Core concerns. The mapping tweaks such a solution would probably require to be&amp;nbsp;palatable are not likely to be useful in other areas of the system.&lt;br /&gt;&lt;br /&gt;So how else would you do this?&amp;nbsp;Using a provider.&lt;br /&gt;&lt;br /&gt;The first step is to define, using an Interface in Core, the query you want to run. Lets say you want to grab all orders above a specific&amp;nbsp;quantity&amp;nbsp;shipped to a specific state. Maybe you want to step though them to find out their frequency and see if you should advise a later&amp;nbsp;ship date&amp;nbsp;to save on freight by combining shipments. Something like that.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;public interface IQueryOrders&amp;nbsp;&lt;/blockquote&gt;&lt;blockquote&gt;{&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; IEnumerable&lt;order&gt; FindOrders(string ToState, int AboveQty);&lt;/order&gt;&lt;/blockquote&gt;&lt;blockquote&gt;}&lt;/blockquote&gt;&lt;br /&gt;&amp;nbsp;Next, you want a place for this to live in your Core assembly.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;public static class Providers&lt;/blockquote&gt;&lt;blockquote&gt;{&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;public static IQueryOrders OrdersProvider { get; set; }&lt;/blockquote&gt;&lt;blockquote&gt;}&lt;/blockquote&gt;&lt;br /&gt;Now, you need to create this provider in the Data assembly.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;public class OrderProvider : Core.IQueryOrders&lt;/blockquote&gt;&lt;blockquote&gt;{&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; public IEnumerable&lt;order&gt; FindOrders(string ToState, int AboveQty)&lt;/order&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// Your Query logic goes here.&amp;nbsp;&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/blockquote&gt;&lt;blockquote&gt;}&lt;/blockquote&gt;&lt;br /&gt;So now we've got the Core assembly setting up a contract, and the Data assembly setting up a facility to handle that contract. All that's left is to connect one to the other. I do this in the UI assembly.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Core.Providers.OrdersProvider = new Data.OrderProvider();&lt;/blockquote&gt;&lt;br /&gt;And finally, you can write your code in Core to consume the output of this provider and act upon it. Not ground breaking, but simple, and useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3702639791878600134-3365544609314688964?l=tomdietrich.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomdietrich.blogspot.com/feeds/3365544609314688964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/iprovider-to-sidestep-dependency.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/3365544609314688964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/3365544609314688964'/><link rel='alternate' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/iprovider-to-sidestep-dependency.html' title='IProvider to sidestep dependency problems.'/><author><name>Dietrich</name><uri>http://www.blogger.com/profile/15573313167900812535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3702639791878600134.post-7315318915380372713</id><published>2010-07-19T12:50:00.000-07:00</published><updated>2010-07-21T05:36:18.655-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Desktop'/><category scheme='http://www.blogger.com/atom/ns#' term='Separation of Concerns'/><category scheme='http://www.blogger.com/atom/ns#' term='Program Architecture'/><title type='text'>Three Tier Structure on a Desktop Application.</title><content type='html'>When you are developing in Visual Studio, the urge is to make a monolithic application. Visual Studio practically &lt;i&gt;begs you to. &lt;/i&gt;It calls out to you with the siren's song of WYSIWYG DB structure diagrams. It tempts you with embedded data providers that serve their function with the minimal amount of code required. It seduces you with &amp;nbsp;auto-generated CRUD functionality that can keep you from having to even think about SQL.&amp;nbsp;Lash yourself to the mast my friends. Don't give in.&amp;nbsp;The up side to these monolithic applications is that they provide a shorter route from &lt;u&gt;F&lt;/u&gt;ile -&amp;gt; &lt;u&gt;N&lt;/u&gt;ew-&amp;gt; &lt;u&gt;P&lt;/u&gt;roject to something you can run and play with. The down side, however, is &lt;i&gt;everything else.&lt;/i&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Monolithic applications built in this&amp;nbsp;manor&amp;nbsp;are difficult, if not impossible to unit test. They are difficult, if not impossible, to migrate from DB structure to DB structure. They make it difficult for you to&amp;nbsp;truly&amp;nbsp;own your Business Logic and not have the class structure dictated to you by a one-to-one relationship between class and table. They limit your freedom, your ability to maintain your work, and, in the long run, are much more expensive to upkeep.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What you want is an application&amp;nbsp;architecture&amp;nbsp;that permits unit testability. One that&amp;nbsp;separates&amp;nbsp;your concerns so that your Data Structure and your Business Logic class diagram only look similar when that&amp;nbsp;similarity&amp;nbsp;fits the needs of both functions. A design that permits you to minimize the unintended impact of code changes as much as humanly possible, and to keep the number of lines required to change any given aspect of it's&amp;nbsp;functionality&amp;nbsp;to the bare minimum. A design that allows you to have more than one UI, if needs dictate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The most simple structure that provides for each of these needs is the three tier structure. It looks like this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8AWt_3xqhwM/TESn3RMiCUI/AAAAAAAAB5E/m1nSQR2_hRA/s1600/3-Tiers-Annotated.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="226" src="http://2.bp.blogspot.com/_8AWt_3xqhwM/TESn3RMiCUI/AAAAAAAAB5E/m1nSQR2_hRA/s400/3-Tiers-Annotated.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;A Core project holds all your business logic. This is where you define the entities that you require to check off all the&amp;nbsp;requirements&amp;nbsp;on the spec sheet. These entities should be entirely code driven- unaware of the fact that they exist on SQL or in any other database structure. Unaware of the fact that they are being manipulated by a Windows program or a Webservice&amp;nbsp;or any other front end. Do what I do, and don't permit the core project to reference System.Data or System.Windows. The reference direction will prohibit it from accessing functions in the Data and UI assemblies.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Data project is where you want all your SQL interaction to reside. It will consist of the mappings of the&amp;nbsp;persist-able&amp;nbsp;business objects to the database behind the scenes, as well as any-and-all direct queries that the UI might need to run. The Data assembly should not know nor care what UI technology it is providing data for, and should not be&amp;nbsp;intelligent&amp;nbsp;about the purpose of the Core objects. As far as Data is concerned, it's only function is to create Core objects and return them to whatever wants them. I prefer NHibernate for a DRM solution in this assembly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally, the UI layer is where you want any and all code relating to the presentation of data and interaction with the end user. This technology could be WPF, or WinForms, or webforms, or Silverlight, or even a webservice. It is whatever makes the most sense. But whatever it is, it should not contain any business logic or sql interaction code.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The hardest part of this structure is keeping yourself honest. It is tempting, hell, even easy, to write business logic in the UI layer by accident. A line of code that starts off as a simple call to a parameterless constructor one day may eventually morph into several lines that instantiate a business object and set up its default values, such as the creation date and name of creator. When requirements for prompts during&amp;nbsp;certain&amp;nbsp;procedures come along, it is very tempting to simply write a call to MessageBox in the Core assembly.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These temptations must be resisted.&amp;nbsp;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3702639791878600134-7315318915380372713?l=tomdietrich.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomdietrich.blogspot.com/feeds/7315318915380372713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/three-tier-structure-on-desktop.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/7315318915380372713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/7315318915380372713'/><link rel='alternate' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/three-tier-structure-on-desktop.html' title='Three Tier Structure on a Desktop Application.'/><author><name>Dietrich</name><uri>http://www.blogger.com/profile/15573313167900812535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_8AWt_3xqhwM/TESn3RMiCUI/AAAAAAAAB5E/m1nSQR2_hRA/s72-c/3-Tiers-Annotated.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3702639791878600134.post-8547893855511193814</id><published>2010-07-16T06:27:00.000-07:00</published><updated>2010-07-21T05:35:20.807-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Structure'/><category scheme='http://www.blogger.com/atom/ns#' term='4 Table'/><title type='text'>Bliss and the Four Table Structure.</title><content type='html'>One of the most common design considerations I need to make in laying down a data structure is the&amp;nbsp;flexibility&amp;nbsp;that the end-user&amp;nbsp;requires. Sometimes it's just the ability to modify what shows up in a drop down box- and then they get a lookup table. Sometimes it's the ability to create and apply properties to business objects- and then they get my standard tag structure (but that's another post). But sometimes, what the end-user really requires is the ability to create their own data structure.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_8AWt_3xqhwM/TEBa9FxsbJI/AAAAAAAAB40/wG8N5or8p80/s1600/4TableStructure2.png" imageanchor="1" style="clear: right; display: inline !important; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_8AWt_3xqhwM/TEBa9FxsbJI/AAAAAAAAB40/wG8N5or8p80/s320/4TableStructure2.png" /&gt;&lt;/a&gt;&lt;/div&gt;Let's say your client wants to be able to attach information to their customer entity. But not just one piece of information- entire sets of it. If their customer deals with a specific process, they want to be able to record a great amount of detail about that process. And they want to be consistent about how they record it across many customers. A notes field is not going to lend itself to that structure. Let's further say that they might want to change what they record about this process&amp;nbsp;tomorrow, and they don't want to have to wait for you to show up, modify a table and re-design a form to have a field for this new piece of data.&lt;br /&gt;&lt;br /&gt;The data that goes into this structure &lt;i&gt;just makes sense&lt;/i&gt;. You would want to capture this stuff anyway, and this format for capturing data works pretty well for allowing your end user to define what they want to capture without a need for your intervention.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://1.bp.blogspot.com/_8AWt_3xqhwM/TEBXB1N3BlI/AAAAAAAAB4s/dqNBfPyPy6U/s1600/4TableStructure.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_8AWt_3xqhwM/TEBXB1N3BlI/AAAAAAAAB4s/dqNBfPyPy6U/s320/4TableStructure.png" /&gt;&lt;/a&gt;I call it the four table structure. It defines what I like to think of as Virtual Tables.&amp;nbsp;This is not ground breaking stuff. You've probably already made a few data structures that act this way without realizing it. What might be different about this is thinking of it as a virtual table. If you were to take the data from our example up there and envision it as an actual table using these mappings, the result would look something like this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_8AWt_3xqhwM/TEBdMWXC02I/AAAAAAAAB48/M_aH_L-DiEM/s1600/4TableStructure3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="116" src="http://2.bp.blogspot.com/_8AWt_3xqhwM/TEBdMWXC02I/AAAAAAAAB48/M_aH_L-DiEM/s400/4TableStructure3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It's a table! &amp;nbsp;It's a freaking table! Made out of data!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3702639791878600134-8547893855511193814?l=tomdietrich.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomdietrich.blogspot.com/feeds/8547893855511193814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/bliss-and-four-table-structure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/8547893855511193814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/8547893855511193814'/><link rel='alternate' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/bliss-and-four-table-structure.html' title='Bliss and the Four Table Structure.'/><author><name>Dietrich</name><uri>http://www.blogger.com/profile/15573313167900812535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_8AWt_3xqhwM/TEBa9FxsbJI/AAAAAAAAB40/wG8N5or8p80/s72-c/4TableStructure2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3702639791878600134.post-3318600348421601853</id><published>2010-07-15T08:02:00.000-07:00</published><updated>2010-07-21T05:36:58.481-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Desktop'/><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Separation of Concerns'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Desktop applications and NHibernate</title><content type='html'>I've been using NHibernate almost exclusively for the last 2 years for all my data access needs. That in an of itself is not remarkable. What does feel remarkable, to me at least, is that I don't really do any web development. Or maybe that isn't remarkable. I'm not sure.&lt;br /&gt;&lt;br /&gt;What I am sure about is that most of the&amp;nbsp;documentation&amp;nbsp;and examples that you commonly encounter with NHibernate are about Blogs, or web stores, or something equally non-desktop based. Maybe as a direct result of this,&amp;nbsp;it took me a good six months of banging my head against the NHibernate learning curve before everything about it really clicked. So, without further ado, here are some things I've picked up.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ITEM THE FIRST: &lt;/b&gt;An ISession and a database transaction are not the same thing. An ISession and a database transaction are not intended to be the same thing. Sessions should open and close transactions every time they interact with the database, but you should never, ever open a transaction and keep it open the entire time the ISession is alive. This will result in table locks galore and more headaches than you will know what to do with.&lt;br /&gt;&lt;br /&gt;That being said, ISessions make sense to hold open in relation to a form- it enables first level caching as a performance booster and most users will intuitively understand that they will sometimes have to close and open or reload a form to see updates&lt;i&gt;.&amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Unfortunately&lt;/i&gt;, this is not one of those problems that single developer testing on a development database is going to enlighten you to. Keeping a Transaction open the entire time a form is open so you can quickly and easily roll back changes might seem like a good idea on the surface! IT IS NOT.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ITEM THE SECOND:&lt;/b&gt;&amp;nbsp;Just because you have "Lazy" Loading doesn't mean you get to be. In my specific application domain, I have several high level domain wide objects or collections of objects that almost everything is related to, like "Company" and "Employee". In earlier versions of my domain, I had these objects related though object references with all the child objects that belonged to them. This resulted in some&amp;nbsp;hideous&amp;nbsp;N+1 problems.&lt;br /&gt;&lt;br /&gt;For the uninitiated, an N+1 problem is when, for every result returned in a query, you run an additional query to fetch related data. If I wanted to show a list of some child object, and include on that list the name of employee who was the owner of that object, I&amp;nbsp;face planted&amp;nbsp;on an N+1 problem. N+1 is probably the biggest trap to avoid when working with NHibernate, because it will &lt;i&gt;destroy&lt;/i&gt;&amp;nbsp;your performance.&lt;br /&gt;&lt;br /&gt;The internet will probably point you towards a more web oriented solution to these issues- which is to tweak your query plan, or your mapping files to perform batch selects. There is nothing wrong with these approaches, but they aren't ideal. You need to know ahead of time what kinds of queries you are going to run to tweak your query plan, and if you edit the mapping files you may introduce some unintended consequences. But we don't have to deal with unknowns in terms of the life span of the assembly, nor do we have to worry about extending the length of our first request and creating uneven performance, so there are other options.&lt;br /&gt;&lt;br /&gt;The plan I settled on was to pre-load these kinds of things. On application_load, I run a series of queries which loads the non-changing parts of the domain into some application static objects. The child objects that refer to these get loaded with only a integer pointing to the unique ID of the static object in a private field from NHibernate, and then I have a simple property that wraps up access to this to make it transparent to the user that I am, in fact, not dealing with these things on a purely object level.&lt;br /&gt;&lt;br /&gt;Not exactly ground breaking, but not exactly something that naturally occurs to people, or me at least.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3702639791878600134-3318600348421601853?l=tomdietrich.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomdietrich.blogspot.com/feeds/3318600348421601853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/desktop-applications-and-nhibernate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/3318600348421601853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3702639791878600134/posts/default/3318600348421601853'/><link rel='alternate' type='text/html' href='http://tomdietrich.blogspot.com/2010/07/desktop-applications-and-nhibernate.html' title='Desktop applications and NHibernate'/><author><name>Dietrich</name><uri>http://www.blogger.com/profile/15573313167900812535</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
