Storing geometries as SDO_POINT_TYPE with Hibernate 5 and Oracle - hibernate-5.x

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.

Related

How to query documents in MarkLogic and process results

I've been working off of the tutorial pages but seem to have a fundamental disconnect in my thinking transitioning off of RDBMS systems. I'm using MarkLogic and handling this database interaction through the Java API focusing on the search access via POJO method outlines in the tutorial documentation.
My reference up to this point has come from here principally: http://developer.marklogic.com/learn/java/processing-search-results
My scenario is this:
I have a series of documents. We'll call them 'books' for simplicity. I'm writing these books into my DB like this:
jsonDocMgr.write("/" + book.getID() + "/",
new StringHandle(
"{name: \""+book.getID()+"\","+
"chaps: "+ book.getNumChaps()+","+
"pages: "+ book.getNumPages()+","+
"}"));
What I want is to execute the following type of operation:
-Query all documents with the name "book*" (as ID is represented by book0, book1, book2, etc)
where chaps > 3. For these documents only, I want to modify the number of pages by reducing by half.
In an RDBMS, I'd use something like jdbcTemplate and get a result set for me to iterate through. For each iteration I'd know I was working with a single record (aka a book), parse the field values from the result set, make a note of the ID, then update the DB accordingly.
With MarkLogic, I'm awash in a sea of different handlers and managers...none of which seems to follow the pattern of the ResultSet with a cursor abstraction. Ultimately I want to do a two-step operation of check the chapter count then update the page field for that specific URI.
What's the most common approach to this? It seems like the most basic of operations...
Try the high-level Java API and see if it works for you. Create a multi-statement transaction with a query by example, then use document operations.
At a lower level, the closest match to a ResultSet is the ResultSequence class. The examples at http://docs.marklogic.com/javadoc/xcc/overview-summary.html are pretty good. For updates the interaction model between Java and MarkLogic is a bit different from JDBC and SQL. There is no SELECT... FOR UPDATE syntax.
The most efficient low-level technique is to select and update in one XQuery transaction, something like a stored procedure. However this requires good knowledge of XQuery. The other low-level approach is to use an XCC multi-statement transaction, which requires a little less knowledge of XQuery.
A minor issue in your code ... you definately do NOT want to end your JSON docuement URIs with "/" as you do in your sample code. You should end them with the ".json" or some other extension or no extension but definately not "/" as that is treated specially in the server.

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;
}

ndb ComputedProperty filtering

I have a User ndb.Model which has a username StringProperty that allows upper en lower case letters, at some point I wanted to fetch users by username but have the case forced to lowercase for the filtering. Therefor I added a ComputedProperty to User: username_lower which returns the lowercase version of the username as follows:
#ndb.ComputedProperty
def username_lower(self):
return self.username.lower()
then I filter the query like so:
query = query.filter(User.username_lower==username_input.lower())
This works, however it only does for users created (put) after I added this to the model. Users created before don't get filtered by this query. I first thought the ComputedProperty wasn't working for the older users. However, tried this and calling .username_lower on an old user does work.
Finally, I found a solution to this is to fetch all users and just run a .put_multi(all_users)
So seems like a ComputedProperty added later to the model works when you invoke it straight but doesn't filter at first. Does it not get indexed automatically ? or could it be a caching thing.. ?
any insight to why it was behaving like this would be welcome
thanks
this is the expected behaviour. The value of a ComputedProperty (or any property for that matter I guess) is indexed when the object is "put". The datastore does not do automatic schema updates or anything like that. When you update your schema you need to either allow for different schema versions in your code or update your entities individually. In the case of changes to indexing you have no choice but to update your entities. The MapReduce API can be used for updating entities to avoid request limitations and the like.

What is the purpose Fluent NHiberate's KeyUpdate method?

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

NHibernate: Return A Constant In HQL

I need to return a constant from an HQL query in NHIbernate
SELECT new NDI.SomeQueryItem(user, account, " + someNumber + ")
FROM NDI.SomeObject object
I am trying for something like above. I've tried this:
SELECT new NDI.SomeQueryItem(user, account, :someNumber)
FROM NDI.SomeObject object
And then later:
.SetParameter("someNumber", 1).List<SomeQueryItem>();
But in the first case I get a 'Undefined alias or unknown mapping 1'. Which makes some sense since it probably thinks the 1 is an alias.
For the second I get a 'Undefined alias or unknown mapping :someNumber' which again makes some sense if it never set the parameter.
I have to believe there's some way to do this.
Please feel free to continue to believe there is some way to do this - but with HQL there isn't!
Why would you want to anyway? If you want to update the value this property to the value you specify, then do so after you've loaded the objects. Alternatively, if your result set doesn't quite match to your objects, you could alway use a SQL query (which you can still do via an NHibernate session). But the purpose of NHibernate is to map what's in your database onto objects, so specifying a manual override like this is quite rightly not allowed.
It sounds like there is a (small?) disconnect between your domain objects and your database model. What about creating a small "DTO" object to bridge this gap?
Have your query return a list of SomeQueryItemDTO (or whatever you want to call it) which, due to the naming, you know is not a true part of your domain. Then have some function to process the list and build a list of true SomeQueryItem objects by incorporating the data that is extraneous to the database.
If you're already using the Repository Pattern, this should be easier since all the ugly details are hidden inside of your repository.