Can I use pivot tables with NHibernate?
Can I write
ID id = new Transaction().GetNextID("[TableName]", "[IDColumnName]")-like codes to increment IDs with NHibernate?
Auto Increment Ids
There are auto-increment id generators available for all databases supported by NHibernate. See generator in the reference documentation.
To use an auto-increment Id property, map it as follows and leave the Id value as the default (0) when creating new entities.
<id name="Id" >
<generator class="native"/>
</id>
You can even roll your own generator by implementing NHibernate.Id.IIdentifierGenerator. However, see this question for a discussion on why you should use the database native auto-increment mechanism.
Pivot Tables
NHibernate has no specific support for Pivot tables. That said, you can map the results of any SQL query to objects using a result transformer. The target object does not need to be mapped, and the columns must match the properties.
Named SQL queries can be defined in your mapping files. You can also use native SQL queries directly. Both types of query support named and positional parameters.
var list = session.GetNamedQuery("query-name")
.SetResultTransformer( Transformers.AliasToBean<Foo>())
.SetString("name", "foo")
.List<Foo>();
var list = session.CreateSQLQuery("SELECT * FROM table WHERE A=? and B=?")
.SetString(0, "foo")
.SetInt(1, 42)
.SetResultTransformer( Transformers.AliasToBean<Foo>())
.List<Foo>();
If you defined a view for a pivot query, you could define a readonly mapped class for it with mutable="false".
Result Transformers
A number of result transformers are available, including:
Transformers.ToList Returns a list of values for each row.
Transformers.AliasToEntityMap Creates a map from column names to values for each row.
Transformers.AliasToBean() Creates an object of the nominated type per row and sets its properties with the value from the column of the same name.
Related
If I have a POCO class with ResultColumn attribute set and then when I do a Single<Entity>() call, my result column isn't mapped. I've set my column to be a result column because its value should always be generated by SQL column's default constraint. I don't want this column to be injected or updated from business layer. What I'm trying to say is that my column's type is a simple SQL data type and not a related entity type (as I've seen ResultColumn being used mostly on those).
Looking at code I can see this line in PetaPoco:
// Build column list for automatic select
QueryColumns = ( from c in Columns
where !c.Value.ResultColumn
select c.Key
).ToArray();
Why are result columns excluded from automatic select statement because as I understand it their nature is to be read only. So used in selects only. I can see this scenario when a column is actually a related entity type (complex). Ok. but then we should have a separate attribute like ComputedColumnAttribute that would always be returned in selects but never used in inserts or updates...
Why did PetaPoco team decide to omit result columns from selects then?
How am I supposed to read result columns then?
I can't answer why the creator did not add them to auto-selects, though I would assume it's because your particular use-case is not the main one that they were considering. If you look at the examples and explanation for that feature on their site, it's more geared towards extra columns you bring back in a join or calculation (like maybe a description from a lookup table for a code value). In these situations, you could not have them automatically added to the select because they are not part of the underlying table.
So if you want to use that attribute, and get a value for the property, you'll have to use your own manual select statement rather than relying on the auto-select.
Of course, the beauty of using PetaPoco is that you can easily modify it to suit your needs, by either creating a new attribute, like you suggest above, or modifying the code you showed to not exclude those fields from the select (assuming you are not using ResultColumn in other join-type situations).
I'm working with the criteria API, querying against a mapping file that I cannot really change. There is a root entity with many child entities joined to it and certain queries have required us to add
criteria.SetResultTransformer(CriteriaSpecification.DistinctRootEntity);
in order to avoid getting duplicate entities when there are multiple SQL result-lines due to the joins. The problem is that now I also want to apply an alias-to-bean transformer, like so:
criteria.SetResultTransformer(Transformers.AliasToBean(typeof(MyDto)));
Using either one of these works great. However, I need to combine them: I want to load only the required columns into a DTO object, and also get only distinct root entities. How can I do this?
To load only required column into DTO you can use projection with DistinctEntityRootTransformer as follows
ICriteria criteria = session.CreateCriteria(typeof(YourEntity));
criteria.SetProjection(
Projections.Distinct(Projections.ProjectionList()
.Add(Projections.Alias(Projections.Property("Property"), "Property")));
criteria.SetResultTransformer(
new NHibernate.Transform.AliasToBeanResultTransformer(typeof(MyDto)));
IList list = criteria.List();
I have a table, CityComplete, with columns "USPSCITY", "STATE" and "ZIPCODE"
I have an existing SQLQuery that distinctly selects USPSCITY and STATE based on a fuzzy search. However, when I call list() I get an exception:
19. ResultSet.getString(ZIPCODE)
java.sql.SQLException: Column 'ZIPCODE' not found.
The SQLQuery's entity is set to the CityComplete object.
Is there any way to have Hibernate not try and get ZIPCODE, or have it be part of the result set in some way?
What's the best way to resolve this, other than using Criteria, setting a virtual column with null data, or just getting a full result set and handling distinction on the code side?
When you perform a regular Hibernate query (HQL or Criteria), Hibernate will try to map the resultset based on the properties of the entities which you specified in the mapping. If you are not bringing the "promised" data from the database, you'll need to handle the mapping by yourself, using a ResultTransformer. In this case, you'd still use your CityComplete, but they will be without a ZIPCODE. Unfortunately, there's not much documentation about how to use a ResultTransformer, but you can take a look at the Hibernate's JavaDoc and see if there's one that you could use. If not, you'd need to implement your own:
http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/transform/ResultTransformer.html
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_
Good afternoon, I'm trying to learn nHibernate and it's not terribly clear.
I need to get the result of an sql query:
select patient.name,
discipline.description,
sum(patient.enddate - patient.startdate) as totaltime
from treatment
join patient on patient.id = treatment.patientId
join discipline.id = treatment.disciplineId
I don't need to persist the result, just display it.
If I use hql directly:
What objects will it instantiate and return to me? Will it dynamically build a list of objects containing fields identical to the columns in the result set? The docs leave out this information.
If I need to make a mapping:
Do you create a mapping to a 'meta' object or to one of the joined tables (say 'treatment')?
Thanks
This can be achieved by using DTO objects ("data transfer objects"). You create an object that contains only the data you wish to return. Add an initializing constructor. Then your hql can be of the form:
select new mydto( x.value, y.value ) from x join x.y;
It doesn't seem to like using aggregate functions in the object constructor though.