<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BarneyBlog &#187; coldfusion</title>
	<atom:link href="http://www.barneyb.com/barneyblog/category/coldfusion/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.barneyb.com/barneyblog</link>
	<description>Thoughts, rants, and even some code from the mind of Barney Boisvert.</description>
	<lastBuildDate>Mon, 02 Mar 2020 13:20:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>CFSCRIPT-based Query of Queries Gotcha</title>
		<link>https://www.barneyb.com/barneyblog/2011/10/19/cfscript-based-query-of-queries-gotcha/</link>
		<comments>https://www.barneyb.com/barneyblog/2011/10/19/cfscript-based-query-of-queries-gotcha/#comments</comments>
		<pubDate>Wed, 19 Oct 2011 15:38:51 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1740</guid>
		<description><![CDATA[I'm hardly the first to blog about this (see here or here), but you're using the new-in-CF9 Query object to execute a query of queries (QofQ), you'll run into scope issues.Â  Specifically, the CFQUERY tag executes in the context it is written, but the Query object is a CFC and so follows all the normal [...]]]></description>
			<content:encoded><![CDATA[<p>I'm hardly the first to blog about this (see <a href="http://christierney.com/2011/02/22/coldfusion-9-query-of-query-in-cfscript/">here</a> or <a href="http://www.mischefamily.com/nathan/index.cfm/2009/10/15/Another-CFScript-Query-Gotcha">here</a>), but you're using the new-in-CF9 Query object to execute a query of queries (QofQ), you'll run into scope issues.Â  Specifically, the CFQUERY tag executes in the context it is written, but the Query object is a CFC and so follows all the normal CFC scoping rules.Â  For example:</p>
<pre>q = queryNew('id,name');
new Query(dbtype='query', sql='select * from q').execute().getResult();</pre>
<p>This code will throw an exception saying "Table named q was not found in memory".Â  Why?Â  Because Query is a CFC, and inside a CFC method invocation, you can't see the var-scoped variables from the calling method (nor the variables scope of the calling template).Â  This is standard CFC behaviour, but is quite different than using the CFQUERY tag.Â  The workaround is to do this:</p>
<pre>q = queryNew('id,name');
qry = new Query(dbtype='query', sql='select * from q')
<span style="color: #ff0000;">qry.setAttributes(q=q);</span>
qry.execute().getResult();</pre>
<p>That places the 'q' variable into the variables scope of the Query instance, so it can be found by the CFQUERY tag inside the execute method.Â  Note that this is NOT thread safe!!Â  If you take this approach, you must create a new Query instance for every thread of execution &#8211; you can't pool them.Â  Normally this isn't a big deal, but that setAttributes call is equivalent to assigning to the variables scope and carries all the lurking problems.</p>
<p>If you like chaining, you can do this (which is functionality equivalent, including the thread safety concerns):</p>
<pre>q = queryNew('id,name');
new Query(dbtype='query', sql='select * from q'<span style="color: #ff0000;">, q=q</span>).execute().getResult();</pre>
<p>Here we're just passing the attribute in via the init method, instead of a separate setAttributes call.Â  Like I said, it's no different in terms of functionality, but it's a lot nicer (I think) in terms of readability and conciseness.</p>
<p>In my opinion, this is sort of broken.Â  ColdFusion is all about server-encapsulated hacks in encapsulation.Â  Think about your use of CFQUERY: you just use it, and CF takes care of getting the right database handles and such for you.Â  It just works.Â  It's totally unencapsulated, but it just works.Â  And it's glorious.Â  The Query CFC has the same characteristics, <em>except for QofQ</em>.Â  Not that I expect it to change, but I'm of the opinion that the Query object ought to work like CFQUERY in this regard.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2011/10/19/cfscript-based-query-of-queries-gotcha/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Need A Job?</title>
		<link>https://www.barneyb.com/barneyblog/2011/05/26/do-you-need-a-job/</link>
		<comments>https://www.barneyb.com/barneyblog/2011/05/26/do-you-need-a-job/#comments</comments>
		<pubDate>Thu, 26 May 2011 23:54:11 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[personal]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1695</guid>
		<description><![CDATA[I have a need.Â  A pressing need.Â  I need new coworkers.Â  Three of them.
Boring stuff first.Â  Mentor Graphics Corp is the EDA industry leader and makes all kinds of crazy design and simulation software for electrical engineers, and now embedded developers.Â  If you have a cell phone or a computer, it's almost guaranteed that you're [...]]]></description>
			<content:encoded><![CDATA[<p>I have a need.Â  A pressing need.Â  I need new coworkers.Â  Three of them.</p>
<p>Boring stuff first.Â  Mentor Graphics Corp is the EDA industry leader and makes all kinds of crazy design and simulation software for electrical engineers, and now embedded developers.Â  If you have a cell phone or a computer, it's almost guaranteed that you're using something which either embeds Mentor IP or was designed/tested/manufactured with the help of Mentor products.Â  The company is about a billion dollars in annual revenue and publicly traded.Â  Our team is currently seven application developers plus a designer, a  front-end developer, a multimedia guy, a content editor, and a couple of  operations people.Â  Plus Ron, our boss.Â  We're hiring three more  application developers.Â  The positions are full-time, on-site, in  Wilsonville OR.Â  Blah, blah, blah.</p>
<p>I work in the corporate marketing department (which is weird, but bear with me) on the web services team which is responsible for pretty much all the public-facing web infrastructure for the company.Â  <a href="http://www.mentor.com/">www.mentor.com</a> is the primary property, but we run the support portal, an internal business intelligence application, corporate blog hosting, and a couple industry journal sites.Â  We own everything that comes after the business requirements; divisions in the company come to us with business problems, and we spec, architect, implement, and host the solutions.Â  Despite the fact we're in the marketing department, IT comes to us for expertise.Â  Our primary platform is Adobe ColdFusion, but we support Groovy, Java,  PHP, and Python for different applications where there was a compelling case to not choose a CFML-based solution.</p>
<p>Now the interesting stuff.</p>
<p>There is a formal job description somewhere, but I don't know where, and I wouldn't link to it even if I did.Â  If you want to work here, you need two things:</p>
<ul>
<li>technical competence</li>
<li>a passion for development</li>
</ul>
<p>We expect you to be able to not only implement a spec, but also design solutions.Â  You shouldn't have to be reminded that not everyone speaks English and that clocks around the world don't all say the same time.Â  You should know why pure functional languages don't have <tt>synchronized</tt> blocks.Â  You should have a preference between <tt>emacs</tt> and <tt>vi</tt> and be able to articulate in two sentences or less.Â  You should have commits to some public VCS repository somewhere.Â  You want to be part of a large non-hierarchical team working on a variety of projects.Â  You should know what MVCC stands for without looking it up.Â  You should want to help the six-months-from-now you have less pain, even if it takes a little more work today.Â  You shouldn't be proficient in all of Java, C#, JavaScript, Python, Ruby, and Lisp.Â  You should be proficient in at least one of them, and be competent in at least one more, and be able to compare and contrast the merits of the rest.</p>
<p>If that sounds like you, drop me an email at barney_boisvert@mentor.com or bboisvert@gmail.com.Â  Ron wants a resume, but I want two paragraphs and ~30 lines of interesting code.Â  Not 40, not 20.</p>
<p>Our hiring process is straightforward: get your info, quick mini-interview via phone, a simple code test, and an on-site interview to  meet the team.Â  Mentor pays competitively, and has exceptional benefits  beyond the salary.Â  Positions are full time, relocation assistance is  likely available if you're not in the area &#8211; working remote is not an option.Â  Ron is very reasonable: if  you're the right person, he'll go to bat for you/him/me to ensure things  work.Â  Everyone here understands that spending a little cash to get the right people pays off every time.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2011/05/26/do-you-need-a-job/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>cf.objective Presentation Links</title>
		<link>https://www.barneyb.com/barneyblog/2011/05/16/cf-objective-presentation-links/</link>
		<comments>https://www.barneyb.com/barneyblog/2011/05/16/cf-objective-presentation-links/#comments</comments>
		<pubDate>Mon, 16 May 2011 19:58:03 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1676</guid>
		<description><![CDATA[If you're looking for slides and/or code from any cf.objective presentations, they're mostly published on the cf.objective site.Â  Visit the schedule page, click on a session title, and there should be a download link beneath the session description.Â  There are still a few missing, but most are there, and the rest should be up in [...]]]></description>
			<content:encoded><![CDATA[<p>If you're looking for slides and/or code from any cf.objective presentations, they're mostly published on the cf.objective site.Â  Visit the <a href="http://www.cfobjective.com/index.cfm/schedule/">schedule page</a>, click on a session title, and there should be a download link beneath the session description.Â  There are still a few missing, but most are there, and the rest should be up in the near future now that the speakers are mostly all home.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2011/05/16/cf-objective-presentation-links/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cf.objective Tomorrow!</title>
		<link>https://www.barneyb.com/barneyblog/2011/05/10/cf-objective-tomorrow/</link>
		<comments>https://www.barneyb.com/barneyblog/2011/05/10/cf-objective-tomorrow/#comments</comments>
		<pubDate>Tue, 10 May 2011 22:33:41 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[cfml]]></category>
		<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[personal]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1661</guid>
		<description><![CDATA[Tomorrow I'll be in Minneapolis for the 2011 iteration of cf.objective.Â  If you've looked at the schedule, you'll know I'm speaking twice: one about progressive enhancement first thing Thursday morning after the keynote, and again Friday right after lunch about migrating your apps to the cloud.Â  You'll also know that there are a hell of [...]]]></description>
			<content:encoded><![CDATA[<p>Tomorrow I'll be in Minneapolis for the 2011 iteration of <a href="http://www.cfobjective.com/">cf.objective</a>.Â  If you've looked at the schedule, you'll know I'm speaking twice: one about progressive enhancement first thing Thursday morning after the keynote, and again Friday right after lunch about migrating your apps to the cloud.Â  You'll also know that there are a hell of a lot of good sessions, so I'm really excited about it.</p>
<p>As is often the case with internet folks, I know a whole lot of people by name and/or handle, but far fewer in person.Â  So if you see me &#8211; I'm the tall, furry guy who isn't Andy Matthews &#8211; please say hello.Â  And as if you didn't need even more incentive, the company I work (Mentor Graphics Corp) for is currently looking to hire a couple more full-time developers out in beautiful Portland, OR.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2011/05/10/cf-objective-tomorrow/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ColdFusion null Gotcha</title>
		<link>https://www.barneyb.com/barneyblog/2011/04/27/coldfusion-null-gotcha/</link>
		<comments>https://www.barneyb.com/barneyblog/2011/04/27/coldfusion-null-gotcha/#comments</comments>
		<pubDate>Wed, 27 Apr 2011 17:36:50 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1650</guid>
		<description><![CDATA[As you probably know, CFML doesn't have any concept of nulls within it's own type system. It has some facilities for dealing with nulls due to interfaces with other type systems (e.g., from Java or JavaScript).Â  At least on ColdFusion, it's not perfect.Â  Consider this code:
s = {
  'javaCast' = javaCast('null', 0),
  'json' [...]]]></description>
			<content:encoded><![CDATA[<p>As you probably know, CFML doesn't have any concept of nulls within it's own type system. It has some facilities for dealing with nulls due to interfaces with other type systems (e.g., from Java or JavaScript).Â  At least on ColdFusion, it's not perfect.Â  Consider this code:</p>
<pre>s = {
  'javaCast' = javaCast('null', 0),
  'json' = deserializeJson('null')
};
structKeyExists(s, 'javaCast'); // false
structKeyExists(s, 'json');     // true
structKeyExists(s, 'missing');  // false
isNull(s.javaCast); // true
isNull(s.json);     // false
isNull(s.missing);  // true
</pre>
<p>As you can see, there is no difference between null and missing.Â  However, the null from the JSON gets deserialized not as a null, but as "null" (i.e., the string containing the letters 'n', 'u', 'l', and 'l').  Wait, what?</p>
<p>I don't think there should be any confusion about how contrived this example is.Â  However, the issue manifests itself any time you're deserializing JSON packets with ColdFusion.Â  So watch out.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2011/04/27/coldfusion-null-gotcha/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Groovy DataSources for Railo</title>
		<link>https://www.barneyb.com/barneyblog/2010/05/25/groovy-datasources-for-railo/</link>
		<comments>https://www.barneyb.com/barneyblog/2010/05/25/groovy-datasources-for-railo/#comments</comments>
		<pubDate>Tue, 25 May 2010 16:39:27 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[railo]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1522</guid>
		<description><![CDATA[If you've ever wanted to do raw JDBC stuff in your ColdFusion applications, you probably know that you can get a javax.sql.DataSource via this code:
createObject("java", "coldfusion.server.ServiceFactory")
  .dataSourceService.getDatasource("myDSN")
Unfortunately, this doesn't work on Railo, because the result isn't actually a javax.sql.DataSource, it just looks like one (see RAILO-43).  To put that another way, it's duck typed.
Fortunately, [...]]]></description>
			<content:encoded><![CDATA[<p>If you've ever wanted to do raw JDBC stuff in your ColdFusion applications, you probably know that you can get a javax.sql.DataSource via this code:</p>
<pre>createObject("java", "coldfusion.server.ServiceFactory")
  .dataSourceService.getDatasource("myDSN")</pre>
<p>Unfortunately, this doesn't work on Railo, because the result isn't actually a javax.sql.DataSource, it just looks like one (see <a ="https://jira.jboss.org/browse/RAILO-43">RAILO-43</a>).  To put that another way, it's duck typed.</p>
<p>Fortunately, Groovy's "fake" interfaces make beating the typechecks fairly trivial (if kind of ugly):</p>
<pre><cfset variables.my.datasource = createObject("java", "coldfusion.server.ServiceFactory")
  .dataSourceService.getDatasource(my.dsn) />
<g:script>
  def rds = variables.my.datasource
  variables.my.datasource = {
    rds.getConnection()
  } as javax.sql.DataSource
</g:script></pre>
<p>The CFSET gets the "datasource" as normal, and then the little Groovy scriptlet simply wraps it with a closure and tells it to pretend to be a javax.sql.DataSource. The game Escape from Tarkov has one important feature: after your death in a RAID, you lose your equipment. To prevent the loss of important equipment in the game, there are special sites with <a href="https://needmana.com/wow-gold/escape-from-tarkov-currency-and-items/">eft roubles</a> you can always get top equipment and kill all pepegas squad. The items you store from needmana will not disappear. There are three types of containers in total. Alpha, Beta, and Gamma. These containers differ in their size. Usually, these containers should store the most important equipment-maps, ammunition, keys, and so on.  In this case we're assuming that the only method on DataSource that will be invoked is getConnection(), which is the usual case.  If you need to support other methods you'd need to go the Map-as-interface route.</p>
<p>Now we can use variables.my.datasource as a javax.sql.DataSource.  Yay!  Unfortunately, you have to use this sort of snippet everywhere you need a DataSource in your Railo apps, but hopefully that'll get fixed.</p>
<p>For more info on Groovy interfaces, the docs are at <a ="http://groovy.codehaus.org/Groovy+way+to+implement+interfaces">http://groovy.codehaus.org/Groovy+way+to+implement+interfaces</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2010/05/25/groovy-datasources-for-railo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CFGroovy at the Tulsa CFUG on May 25th</title>
		<link>https://www.barneyb.com/barneyblog/2010/05/18/cfgroovy-at-tulsa-cfug-may-25/</link>
		<comments>https://www.barneyb.com/barneyblog/2010/05/18/cfgroovy-at-tulsa-cfug-may-25/#comments</comments>
		<pubDate>Tue, 18 May 2010 16:35:52 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1520</guid>
		<description><![CDATA[Next Tuesday (May 25th), I will be presenting CFGroovy to the Tulsa CFUG via Connect.Â  Details are at http://www.tulsacfug.org/meetings.cfm, but the important bit is that it's at 12:30 central time, not in the evening.Â  Steve Bryant &#8211; who manages the group &#8211; graciously extended a general invitation to anyone else who would like to join [...]]]></description>
			<content:encoded><![CDATA[<p>Next Tuesday (May 25th), I will be presenting CFGroovy to the Tulsa CFUG via Connect.Â  Details are at <a href="http://www.tulsacfug.org/meetings.cfm">http://www.tulsacfug.org/meetings.cfm</a>, but the important bit is that it's at 12:30 central time, not in the evening.Â  Steve Bryant &#8211; who manages the group &#8211; graciously extended a general invitation to anyone else who would like to join via Connect.Â  I'll post again with more details as we get closer to the event.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2010/05/18/cfgroovy-at-tulsa-cfug-may-25/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Should It Just Work?</title>
		<link>https://www.barneyb.com/barneyblog/2010/04/25/should-it-just-work/</link>
		<comments>https://www.barneyb.com/barneyblog/2010/04/25/should-it-just-work/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 04:38:48 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1489</guid>
		<description><![CDATA[Last Wednesday evening Sean Corfield and I were chatting over beers and he caught me by surprise with a statement he made.Â  We were talking about the ORM functionality in CF9, and he liked how it just worked.Â  You invoke a setter, and it gets to the database with nothing else.Â  I agree in theory, [...]]]></description>
			<content:encoded><![CDATA[<p>Last Wednesday evening <a href="http://www.corfield.org/">Sean Corfield</a> and I were chatting over beers and he caught me by surprise with a statement he made.Â  We were talking about the ORM functionality in CF9, and he liked how it just worked.Â  You invoke a setter, and it gets to the database with nothing else.Â  I agree in theory, but not in practice.</p>
<p>It had honestly never occurred to me that someone would actually <em>want</em> to have stuff get to the database without any control over it.Â  Transactionality is such an ingrained part of my being that the mere thought of writing to the database outside an explicit transaction never even entered my mind.</p>
<p>There have been a number of discussions about transactions on the <a href="http://groups.google.com/group/cf-orm-dev">cf-orm-dev</a> mailing list.Â  Often prompted by someone mentioning some problem and me jumping down their throats about how they better use transactions.Â  But here's a very experienced developer who I know full well intimately understands transactionality actually saying with complete honesty that he likes to have it just work.</p>
<p>I'm personally against this approach: if something goes awry your database could well get jacked, and no one wants that.Â  Though I nearly always apply transactionals via AOP, and both Sean and I agreed that assuming AOP familiarity is unreasonable for people using CF9 ORM.</p>
<p>The conversation quickly moved on from there (I believe <a href="http://www.scala-lang.org/">Scala</a> was the next topic), but that brief moment of complete surprise stuck in my mind.Â  I certainly don't claim to know it all, but I know that I have opinions that are not shared by everyone.Â  However, the dismissal of ACID like that was a shock.Â  I respect Sean's opinion very much, and while I will continue to wrap all my saves in a transaction, things are clearly not as cut and dried as I think they are.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2010/04/25/should-it-just-work/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Domain Model Integrity</title>
		<link>https://www.barneyb.com/barneyblog/2010/04/14/domain-model-integrity/</link>
		<comments>https://www.barneyb.com/barneyblog/2010/04/14/domain-model-integrity/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 16:35:23 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1478</guid>
		<description><![CDATA[Unlike my last several posts, this one isn't ORM related.Â  At least not directly.Â  If you're using ORM, you necessarily care about your domain model's integrity, as it's a prerequisite for ORM doing it's job, but it has nothing to do with ORM specifically.Â  The point of a domain model is to be a representation [...]]]></description>
			<content:encoded><![CDATA[<p>Unlike my last several posts, this one isn't ORM related.Â  At least not directly.Â  If you're using ORM, you necessarily care about your domain model's integrity, as it's a prerequisite for ORM doing it's job, but it has nothing to do with ORM specifically.Â  The point of a domain model is to be a representation of your business rules and logic, and that means it needs to be internally consistent.</p>
<p>If you're building a SQL-heavy, procedural application, the database is probably the only place your domain model is represented.Â  But if you're building an object oriented application, your domain model will also be represented in memory as object graphs.Â  In almost all cases, a given object graph is only a small slice of your entire domain model, but it is a representation and must be kept consistent.</p>
<p>Here's an example of a very simple domain model consisting of Person and Pet classes, where a Pet has an owner (a Person), and a Person has a collection of Pets:</p>
<pre>component Person {
  property name="name" type="string";
  property name="pets" type="array[Pet]";
}

component Pet {
  property name="species" type="string";
  property name="owner" type="Person";
}</pre>
<p>Just to reiterate, these are NOT persistent types.Â  They're simple types for in-memory use only.</p>
<p>So what semantics does this model imply?Â  Or to rephrase, what invariants does this model carry?Â  The most important semantic is that the relationship between pets and their owners is expressed from both sides (both classes).Â  More explicitly stated, the domain model is structured such that if you have a Person you can get their Pets, and if you have a Pet, you can get their owner (a Person).Â  The implications of this is expressed in these two invariants:</p>
<pre>assert pet.owner is null || pet.owner.pets contains pet
assert person.pets.every { pet.owner == person }</pre>
<p>The first one states that if a Pet has an owner, that owner's "pets" collection must contain it.Â  The second one states that every Pet in a Person's "pets" must have that Person set as it's owner.Â  I'm trying to be really deliberate in spelling this out, because it's <em>really</em> important.</p>
<p>Just for a moment, let's take a detour to the relational database world.Â  If we were to express this domain model in the database we'd have a Person table and a Pet table, and the Pet table would have a foreign key (likely named 'owner_id') that references the Person table's primary key.Â  SQL allows us to traverse the relationship expressed by that foreign key in either direction, so both relationships (Person-&gt;Pet and Pet-&gt;Person) are expressed in a single place (the foreign key column).Â  Both directions are represented together.Â  A foreign key constraint (which all RDBMSes support), on the column is doing nothing more than instructing the database to enforce these invariants.Â  This is all second nature, and we don't even think about it when we use a database to represent our domain model.</p>
<p>Now back to the in-memory representation.Â  We still need to enforce these invariants, but in memory we have to deal with references (pointers), and references only point in one direction.Â  That's why we have to have both the 'pets' property (a Person's references to Pets) and the 'owner' property (a Pet's reference to a Person), but in the database we only need one foreign key column (Pet.owner_id).Â  The relationship between Person and Pet objects is actually expressed in a <strong>pair</strong> of references.</p>
<p>The problem with this arrangement is that you, in effect, double represent your relationships.Â  Both invariants must remain true, and since each invariant is represented by it's own reference in the model, you have to synchronize changes to those references.Â Â  When you set the owner of a Pet, you must also add that Pet to the owner's "pets" collection.Â  When you remove a Pet from a Person's "pets" collection, you must also remove the Pet's owner reference.Â  If you don't keep these in sync, one of your invariants will be false, and that means your domain model is in an invalid/inconsistent state.</p>
<p>When your domain model is in an invalid state, your application falls apart.Â  Every assumption you make in your application is suddenly unreliable, because they're predicated on your business rules, and your business rules are expressed through your domain model.Â  An invalid domain model means your business rules were violated, and anything you do from this point forward will be suspect.Â  I'm going to say it again: this is <strong>really</strong> important.Â  If your domain model is in an invalid state, your application has failed.Â  Period.Â  End of story.Â  Your only recourse is to revert it back to it's last known consistent state and throw away all pending operations.</p>
<p>What about relationships that are not bi-directional?Â  For example, perhaps your model has PrivateEye and Subject types.Â  Clearly the PrivateEye needs to know about his Subject, but it'd be kind of silly if the Subject knew about the PrivateEye.Â  In this case the relationship only moves one way, so there is only one reference (from PrivateEye-&gt;Subject), and <em>there is no invariant</em>.Â  When we put this in the database, however, we have exactly the same structure as the bi-directional Person&lt;-&gt;Pet relationship: a foreign key that can be traversed in two directions.Â  With the database representation of the model you <strong>can't</strong> express the concept of a one-directional relationship.Â  This is a powerful differentiator for in-memory models, since it gives you much finer control over the semantics of your model than a database could ever provide.</p>
<p>So where does this relate to ORM?Â  Just like everything else in your application, Hibernate depends on your invariants being true in order to persist your model to the database.Â  If they're not true, Hibernate can't hope to do it's job correctly.Â  A huge number of "problems" that people starting out with Hibernate face have nothing to do with Hibernate itself, but rather are caused by an invalid in-memory domain model.Â  Coming from the world of procedural, SQL-based persistence, you don't necessarily have to worry about an in-memory domain model's integrity, which means that you can write what amount to buggy applications where the bugs never manifest themselves.</p>
<p>Bottom line is that if you're using an in-memory domain model, you simply <strong>must</strong> ensure the invariants of that model remain true.Â  More specifically, you <strong>must</strong> set both sides of every bi-directional relationship.Â  If you don't, you're just asking for punishment, both from your software tooling and from users/clients of your application.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2010/04/14/domain-model-integrity/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Want Multiple Persistence Contexts in CF9 ORM?</title>
		<link>https://www.barneyb.com/barneyblog/2010/04/12/want-multiple-persistence-contexts-in-cf9-orm/</link>
		<comments>https://www.barneyb.com/barneyblog/2010/04/12/want-multiple-persistence-contexts-in-cf9-orm/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 00:37:17 +0000</pubDate>
		<dc:creator>barneyb</dc:creator>
				<category><![CDATA[coldfusion]]></category>
		<category><![CDATA[orm]]></category>

		<guid isPermaLink="false">http://www.barneyb.com/barneyblog/?p=1476</guid>
		<description><![CDATA[I do.Â  Because god knows front controllers and persistence layers don't have a one-to-one correspondence.Â  Turns out that through the magic of application switching you can do it, as long as you're careful with your sessions.Â  Not going to go into details right now, but this code works (and does what you'd expect):
&#60;cfapplication name="ormtest1" /&#62;
&#60;cfset [...]]]></description>
			<content:encoded><![CDATA[<p>I do.Â  Because god knows front controllers and persistence layers don't have a one-to-one correspondence.Â  Turns out that through the magic of application switching you can do it, as long as you're careful with your sessions.Â  Not going to go into details right now, but this code works (and does what you'd expect):</p>
<pre>&lt;cfapplication name="ormtest1" /&gt;
&lt;cfset companies = ormExecuteQuery('from Company') /&gt;
&lt;cfinclude template="../app1/dsp_home.cfm" /&gt;

&lt;cfset ormCloseSession() /&gt;

&lt;cfapplication name="ormtest2" /&gt;
&lt;cfset people = ormExecuteQuery('from Person') /&gt;
&lt;cfinclude template="../app2/dsp_home.cfm" /&gt;</pre>
<p>Here's the Application.cfc that this snippet runs under:</p>
<pre>component {
 this.name = "ormtest3";
}</pre>
<p>No ORM awareness at all.</p>
<p>The primary gotcha is that the other applications (ormtest1 and ormtest2) have to have been previously initialized (which you can do with a simple HTTP GET), but this allows you to mix multiple persistence contexts together (much like you can with normal Hibernate), and beat the stupid Application.cfc binding to some degree.Â  You still can only exist in a single context at any given moment, but you can switch back and forth any place you can close/reopen a session.</p>
<p>And for those of you who are thinking ahead, no, you can't manually manage your session objects instead of letting CF.Â  You can get a cross-application reference to the SessionFactory without much issue, and you can create a session, and you can even query for entities, but when you get to traversing lazy-loaded relationships it bombs out for some reason.Â  CF needs to have control over the active session or it doesn't work.Â  Rather sad, but at least running multi-persistence-context apps <em><strong>is</strong></em> possible, even if not concurrently.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.barneyb.com/barneyblog/2010/04/12/want-multiple-persistence-contexts-in-cf9-orm/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
