Before ORM, if I wanted to display the combined output of a normalized table, I’d just do a quick CFQUERY, join the tables on the fields I want and display the output. I just can’t get my head wrapped around it using ORM.
For example with these two tables:
customers
(id,
name,
customerType)
customerTypes
(id,
Name)
How would you create a single entity you can load to display the following when the customerType field in customers links to an id in customerTypes?
customers.id, customers.name, customerTypes.name
All of the ORM relationship examples I’ve walked through for some reason can’t make me understand how to do it. It seems so simple it’s killing me. Any help shedding some light on this would be appreciated!
Or alternatively
<cfproperty name="type" type="string" column="Name" table="customerTypes" joincolumn="id">
see Join mapping in a CFC
So in your Customers CFC you will need something like this:
<cfproperty name="customerType" type="CustomerTypes" fieldtype="many-to-one" cfc="CustomerTypes" fkcolumn="id" lazy="true" />
Then you should be able to dump an instance of a Customers object and see that it has a customerType property and hence you can write something like this:
<cfset cust = entityLoad("Customers", 1) />
<cfset type = cust.getCustomerType().getName() />
Hope that helps!
Related
I would need to store the following value V in a database. An instance of V is linked with a certain record in a certain table. The problem with V is that it has a resemblance to a union type and can indicate three things:
V has an integer value, meaning that the value should be used for the record in question.
V is absent, i.e. NULL, meaning that a global setting takes precedence for the record in question.
V has a meaning of "ANY", meaning that no value should be used for the record in question.
1 and 2 are easy (make it a NULLable integer column), but how to deal with 3? Now I don't feel comfortable using a special numeric value for indicating the ANY state, because e.g. -1 and 0 are totally valid values for case 1.
What has come to mind so far is
Putting this union type into a separate table that has two columns, one for the numeric value and one for the ANY condition (boolean), and a nillable foreign key reference to it.
Storing it as a VARCHAR column and using some special character (e.g. "*") for ANY state.
Is there any "industry standard" way of doing this? :)
For reference, this union type looks something like this in XSD representation:
<complexType name="V">
<choice>
<element name="anyValue" type="xs:string" fixed="" />
<element name="numericValue" type="xs:int" />
</choice>
</complexType>
<complexType name="E">
<sequence>
<element ... />
<element ... />
<element name="configValue" type="V" minOccurs="0" />
</sequence>
</complexType>
I would solve it as either.
Nullable foregn key. And in the foregn key table there would be a row that indicates that it has the "any state".. for example has all columns as null.
or addin a int/boolean column to inditake an overiding state.
Please don't use varchar for linking to other tables...
I have seen many solutions to this problem and all of them have serious issues. This is never going to be pretty. And try to tailor your solution for the code that is going to consume this mess. Make it as simple for that as you can. In those situations readability is king.
But best advice is never to get into those situations but that I know is not always wihtin your power
I have a DB-intensive function defined in MS SQL that computes a read-only property (LastCompletedDate) of an Inspection object. I don't usually need this information, so I'm not mapping it in Inspection.hbm.xml.
When I do need the info, I want to take an IEnumerable collection of Inspections, query the database to find their LastCompletedDate, and fill that in for each. Ideally, without making a separate trip to the database for each Inspection. I'm having trouble finding a way to do this in NHibernate (I'm a relative newbie to NHibernate). I'm thinking of something like:
CurrentSession.CreateQuery(
"select InspectionId, dbo.fn_GetLastCompletedDate(InspectionId)
from Inspection where InspectionId in :idList")
.SetParameter("idList", from InspectionList select InspectionId)
.List();
followed by a loop to pull out the dates and add them to the Inspection objects.
Is there a better way to do this? And what syntax do I need?
There are two possible options which I can think of.
Mark the property as lazy load
<property name="LastCompletedDate"
lazy="true"
formula="dbo.fn_GetLastCompletedDate(InspectionId)"/>
When performing a query to get all Inspection objects this property will not be loaded.
CurrentSession.CreateQuery("from Inspection")
.List<Inspection>();
But when including a hint this property will be loaded along with all other properties.
CurrentSession.CreateQuery("from Inspection fetch all properties")
.List<Inspection>();
The disadvantage of this approach is that this hint is only available when using HQL. Further details can be found here
http://ayende.com/blog/4377/nhibernate-new-feature-lazy-properties
The second option is to use a component with lazy load enabled.
<component name="lazy_load_items" lazy="true">
<property name="LastCompletedDate"
formula="dbo.fn_GetLastCompletedDate(InspectionId)"/>
</component>
Again this is lazy loaded so a normal query against the Inspection entity wouldn't result in the function being called for each row
CurrentSession.QueryOver<Inspection>.List();
But it can be eager loaded via any of the query APIs
session.QueryOver<Inspection>()
.Fetch(i => i.lazy_load_items).Eager
.List();
This disadvantage of this approach is that is requires an extra class to be created just to contain your single property.
UPDATE
On further testing it looks like eager loading of components only works with HQL using the fetch all properties hint. So the query example I gave is wrong and therefore so are the advantages for the component approach.
Is there a way in NHibernate to map the result of a count query to a property on a class? I'd like to do this in the XML mapping.
I know I could formulate this via code (either with a construct that actually queries the count, or by cheating, doing the full query, and counting the resulting items), but it would be nice if I could write some short SQL or HQL and jam that into my XML mapping, somehow.
A concrete example. My DB has these tables -
Entry
Id
BodySummary
Comment
Id
EntryId
Body
I want to get a summary of entries. For each of the entries, I want to get the comment count (and body summary).
FYI: I've omitted irrelevant parts of my DB, like authors, entry title/body, timestamps, etc. This of course should have no bearing on the part of the query I am asking about.
I don't think you can do it with HQL. But here's how to do it with SQL:
<class name="Entry" .... >
<id>
//ID Strategy
</id>
<property name="BodySummary" />
...
<property name="CommentCount" formula="(SELECT COUNT(*) FROM Comment c WHERE c.EntryId = Id)" type="Int32" />
</class>
Important to note:
Wrap the sql in parenthesis - it will error if it is not wrapped
This is not HQL - you have to use the database column/table names not your mapped classes/properties
Provide a return type so NHibernate knows how to map it back to the property
You will probably want to make this a readonly field but this is the basics of how you would map it.
The resultant SQL would be something like this:
SELECT this_.Id as Id11_0_,
this_.BodySummary as BodySummary10_11_0_,
(SELECT COUNT(* )
FROM Comment c
WHERE c.EntryId = this_.Id) as formula0_0_
FROM Entry this_
I am using nhibernate for my OR persistence and I store a list of doubles into a table using the following mapping (where the list is embedded in another class).
<list name="Values" access="field" table="Values_double" >
<key column="variable_id"/>
<index column="no_data_values_list_index"/>
<element column="value" type="System.Double"/>
</list>
This works fine except when I try to store double.MinValue or double.MaxValue. I get an error
when reloading from my DB saying:
System.OverflowException: Value was either too large or too small for a Decimal.
Which seems to be related to NHibernate storing the doubles as 'NUMERIC' values in my sqlite dBase. The conversion back seems to go broke. Any suggestions are very welcome.
Greetings,
Martijn
In the end I solved it by introducing another custom IUserType for this simple problem :(
I have no experience with SQLite, but you can override NHibernate's choice of SQL datatype by using the sql-type attribute in the mapping. This might help if NUMERIC is not appropriate for the given circumstance.
For example:
<property name="Foo" type="String">
<column name="foo" length="64" not-null="true" sql-type="text"/>
</property>
When I call EntityLoad does it load ALL the data in the table or just sets up a reference or something, because say if i do this:
<cfset test = EntityLoad("Table") />
and then do:
ArrayLen(test)
I get the number of rows in the database. If its doing that then it should be loading all the data, and that is really inefficent, say I have a table with 20x10^5 rows or something, it'll be horrible to load all data just to get the length of the table.
Without seeing your code, I don't know exactly what you're talking about, but here's the run-down:
EntityLoad w/ 1 argument (the Entity name) is going to load all the Entities with that name from the DB. It does however take some additional (optional) arguments to adjust it's behavior. Instead of describing all of them here I'll point you to the beta documentation and a site giving some further exmaples:
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WS02BE9BC5-8206-434b-8486-95CD09CDB985.html#WSf01dbd23413dda0e54af3c7912012f78097-7ff8
http://www.coldfusion-ria.com/Blog/index.cfm/2009/7/22/ColdFusion-9s-ORM-Entity-Load-Functions
To do what you are trying to do efficiently without incurring a select * on your table, use HQL.
<cfset hqlQuery = "select count(*) From person" />
<cfset results = ORMExecuteQuery(hqlQuery)[1] />