What is the purpose Fluent NHiberate's KeyUpdate method? - nhibernate

I have a collection mapped as a query only property following Ayende's example. My mapping is:
HasMany<Employee>(Reveal.Member<Company>("_employees")).Access.None();
This worked fine, except when I load a Company the foreign key Employee.CompanyId is updated to null. This occurs even if I don't update Company and the generated SQL only includes the CompanyId in the update list even though I have not mapped Employee to update changed properties only.
I tried using NoOp (they're synonyms I think) and declaring the employees collection as a public property instead of a private field. I was finally able to fix it by changing the mapping to:
HasMany(Reveal.Member("_employees")).Access.None().Not.KeyUpdate();
What is the purpose of KeyUpdate and what is the equivalent XML mapping? Why is it needed for a query only property? My assumption was that setting access to none or noop would prevent any changes.

Jamie
You can generate the hbms from your AutoPersistenceModel and have a look at the xml if you are still interested. Just something like
model.CompileMappings();
model.WriteMappingsTo(outputDir);
As an aside, have you had a look yet # ConfOrm. I suspect this will gain increased traction given the dev, but haven't spent much time with it yet.
HTH,
Berryl

Related

Storing geometries as SDO_POINT_TYPE with Hibernate 5 and Oracle

I am using Hibernate 5.1.0.Final in a Java application for database persistence. That will be handy for us as we expect to hit Oracle and Postgres instances, so we can have this ORM as an abstraction layer.
In a former issue when querying geometries using Hibernate-spatial I posted some of my configuration.
The problem now is when we persist some geometry fields in Oracle. In my POJO I have an import :
import com.vividsolutions.jts.geom.Geometry;
So that I define the following attribute in my class :
#Column(name = "geom")
protected Geometry geom;
It gets persisted and I can use predicates to query it. But looking inside the database I can see the content of the geom field is :
MDSYS.SDO_GEOMETRY(2001,4326,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1,1),MDSYS.SDO_ORDINATE_ARRAY(0.094,51.488))
Instead of what I would like, which is faster to query and is recommended by Oracle :
MDSYS.SDO_GEOMETRY(2001,4326,MDSYS.SDO_POINT_TYPE(0.094,51.488,NULL),NULL,NULL)
What should I do in order to store this as a point (SDO_POINT_TYPE) and not as an array (SDO_ELEM_INFO_ARRAY) ?
EDIT : I tried changing to Point as shown below, but it didn't make a difference, as far as I can tell.
import com.vividsolutions.jts.geom.Point;
(...)
#Column(name = "geom")
protected Point geom;
It looks to me that currently there is no way to force Hibernate to store points as points instead of an array of coordinates. I went deeper into this and I came out with a tweak to the source code mostly for me, but also for those who need to do so.
I created a pull request to the original project. Even though it may or may not be considered for the master, anybody can potentially create their own customized version of OracleJDBCTypeFactory.java taking it from here :
https://github.com/GeoLatte/geolatte-geom/pull/42
Update : This was merged into master. It should be ready for next release of geolate-geom. As per #maesenka 's comment :
You must set a system property GEOLATTE_USE_SDO_POINT_TYPE=true to enable this feature.

Hibernate reverse engineering of a PostgreSQL database

I am having some trouble generating my DAO/POJO code using Hibernate for a PostgreSQL database written using the CamelCase notation. Everything works fine until the code generation time: only my lowercase tables are generated!
If I have a table called Person, the Hibernate Configurations View will show it but without any attributes. Say I have another table, car, it will be shown with all of its attributes. On code generation time, furthermore, car will appear in the destination package, while the CamelCase tables won't, as it is completely ignored.
I found a way of overriding the default metadata generation class (JDBCMetaDataDialect), but it doesn't work. Even if it did work, I think my POJO/DAO objects would not work, because the PostgreSQLDialect dialect would handle the lowercase tables (and attributes?) in a wrong way.
How can I solve this issue? It looks like a bug, but I'm not sure of it.
I ended up always returning true from my generation method:
public boolean needQuote(String name) {
return true;
}

Fluent NHibernate - HasMany mapping with condition

I have a HasMany mapping that needs a condition. I have this partially working, but there's got to be a better way than what I'm doing. The condition I'm using needs to look at a property on another table that I'm joining to. What I have so far is:
HasMany<MetaData>(x => x.MetaData).Table("MetaData")
.KeyColumn("DefinitionID")
.KeyColumn("TableID")
.Where("metadatade1_.SourceTable = 'Providers'")
.Cascade.SaveUpdate();
In the code above, the where clause is referencing "metadatade1_", because it's trying to fully qualify the name, and that is the name NH is generating. I've tried using "MetaDataDefinitions.SourceTable" (MetaDataDef... is the physical table name), and also just "SourceTable" by itself, however none of these worked.
Is there a way to not have it try and fully qualify the name on the condition and just pass "SourceTable='Providers'" OR is there a way I can have it reference the generated name without me having to manually plug it in?
In short, no. The Where method (and respectively the where= attribute in HBM.XML) accept only raw sql, and as such is prone to the problems you're seeing.
Your best option is to not use a collection and instead rely on a query to retrieve your metadata instances.

NHibernate: Lazyload single property

I have currently moved my blogengine over from Linq2Sql to NHIbernate.
I'm stuck at the following performance problem:
I got one table: 'Posts', that has Id, Title, PostContent, DateCreated collumns and so on.
The problem is that, when I'm creating the "Recent posts list", I don't want the whole PostContent.
In Linq2Sql you can set lazy loading on a single property, so it won't be part of the SQL query until you actually ask for the property.
I tried doing this with Fluent NHibernate, by doing this:
Map(x => x.PostContent).LazyLoad();
It didn't work out. Googling around, it seems that NHibernate doesn't support this, so my question is, how can I fix this?
Is it really not possible to lazy load my property without moving the content to a seperate table?
Thanks in advance!
Update: this capability is now available in the NHibernate trunk.
See details on Ayende's blog, where the sample is exactly the scenario you describe here.
Here is how you can achieve what you want (kind of lazy loading but not the same)
var posts = NHibernateSessionManager.Session.CreateQuery("Select p.Id as Id, p.Title as Title, p.DateCreated as DateCreated from Post p")
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof(Post)))
.List<Post>();
What the AliasToBean is intended for is, doing selects for specific columns (usually from more than one entities) and return a strongly typed collection instead of a System.Object[].
Now if you Bean (class) is your Post class then it will popultate to that class ONLY the requested columns and nothing else.
What you will NOT be having though is a collection of NHibernate managed objects. All Posts in the returned lists are detached non controlled objects.
For doing things like "getting all recent posts" without having to get the most "heavyweight" columns of your entity while not having to create other classes to convert the data to, the above solution is kind of perfect.
Check this out for more info:
NHibernate: returning a strongly typed list having applied an aggregate function
This is not possible when PostContent is mapped to the same table, because the performance difference is not significant in 99% of the situations. When you are in the 1%, you can consider using handbuild sql instead of a orm for that case.
Lazy/Eager loading is not possible at all with linq to sql (out of the box) as far as I know.
What you can do create a different class with the data you want to select and just select that data into a new object.

Can I get NHibernate to enforce that a string property is non-empty?

I know about the not-null attribute. Is there one for enforcing the minimum length of a string property? I don't want empty strings in my database.
I don't know of anything in the mapping file that will let you do this (and I don't see anything in the schema). You could probably define a custom type using NHibernate.IUserType and build your logic into that type (if the string is empty save null). Here is an example of building an IUserType (it would be easy to change this example code to work for you)
The other option is to take advantage of NHibernate.Validations and to handle the validation logic before getting to the point where you are saving the entity to the database.
You are looking for NHibernate Validator! There's a blog post here showing some of its goodness.