Hibernate XML Mapping in Java - java

Edit: I want to change the question a little :-)
I want to save a SaveGame Objet in a SQL database with Hibernate XML. All i want to is to save it. My problem is taht i cant find a way how to do it. I searched now for 3 hours on the internet and didnot find a solution.
All i want to do is to save a integer array as a normal value into my database. I found during my search i can do this with a blob column. But nowhere on this great internet i found the way how to do it. I simply search for a person that can show me how to do it right. Becasue all my tried failed. And i am frustrated now.
My Class that i want to save looks like this:
public class SaveGame implements IDBObject {
int id;
String username;
int basic_game_id;
List<Integer> route = new ArrayList<Integer>();
/*getter + setter */
The SaveGame table should look like this:
ID | username | basic_game_id | route |
1 | Maxi | 1 | xxxxx |
I hope this time its clear what i want to do. I dont have to save every single array entry. I just want to save the whole array in the route column. And i cant find out how i can do this!
Old Question:
I try to map a Integer Array to my database with Hibernate.
This is how my Class looks
public class SaveGame implements IDBObject {
int id;
String username;
int basic_game_id;
List<Integer> route = new ArrayList<Integer>();
/*getter + setter */
My mapping xml looks like this:
<class name="com.travelsales.base_classes.SaveGame" table="SAVEGAME">
<meta attribute="class-description">
This class contains the Save games.
</meta>
<id name="id" type="int" column="id">
<generator class="native"></generator>
</id>
<property name="basic_game_id" type="int" column="basic_game_id"></property>
<property name="username" type="string" column="username"></property>
<list name="route" column="route">
<element type="int"></element>
</list>
</class>
Well i cant find the mistake.
My problem is that i must have an error in the xml mapping part. If i delete the list everything works fine. I want to save integer array or integer list in my database. And i think i have a mistake in the way i do it.
With this code i get the following error:
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.travelsales.controller.MainController.main(MainController.java:42)
Caused by: org.hibernate.InvalidMappingException: Could not parse mapping document from resource Hibernate Config/mapping.hbm.xml

Not sure what you are trying to achieve, do you want to the route to be stored in separate table (to be searchable, etc) or are you happy to have it in same row as your SaveGame.
If your case is really as simple as you presented I would recommend storing in in the same row to save on fetching the int values from the join.
Map the property to a blob column and all is done. I am not using the xml configuration so dont know the syntax but with JPA annotations it is solved by the code:
#Lob
List<Integer> route;
If your hibernate version do not handle interfaces (you will get error messages), change the property declaration form List to ArrayList (which is serializable, so it can be saved as bytes in the blob column).

Well, After all my trys and after all my study from online Documents. Maybe one day another person will have the same problem I had.
Its very simple i was searching for Hibernate types and I found this sentence:
If the type you have is no Basic Hibernate Type and you only want to save it in 1 Column dont write in the Hibernate XML a type and let hibernate decide which typ to use.
If you make your property like normal with name column and type. Hibernate will try if the type is possible for yoru input in my case a int Array. And Hibernate will answer you that the type is unknown. If you set the type to byte[] hibernate will answer you : Do not know to convert int array to byte array.
The Solution is simple just do not set type. Write the property like this:
<property name="route" column="route"/>
Hibernate will now look up which type you will need and set it for you. And everything works fine, and like you want to do it. On the internet you will find alot of resources for array, set and list. All this things will provide a new Tabel special for you array.
If you want to do this go check the internet its full with, helpfull examples. If you just want to save Objects and Hibernate dont know the type just dont set type in your XML.

Related

How do I store an integer using ColdFusion ORM?

TL:DR;
What's the proper syntax/workaround/hack for CF ORM components which have foreign key constraints?
ColdFusion + Integers
Storing a variable as an integer should be an easy programming question, right? Find the appropriate function in the language's documentation (if you can't recall it off the dome) which will say returns: int (owtte) and use that.
Not with ColdFusion.
Some of you may already be aware of ColdFusion's various issues with integers but the one which is currently causing my rapid hair-loss is that ColdFusion will sometimes store your "integer" as either a string, double or long. Now, for most use cases this is not a functionality-breaking issue and is often overlooked/ignored/undiscovered. The exception, in my case, is when ORM comes into play. Of course, as any sensible developer would, I am recognising the possibility of this being down to user error somewhere.
The Problem
The problem occurs whenever CF attempts to interact with the DB. If there is a field which is a foreign key and type 'integer', CF throws a Hibernate Exception with the following message:
java.lang.Integer
That's it. Helpful, right? I found out that this "error message" is explicitly the variable type you're passing into that field, so if you pass a double into the field erroneously, the error message would read java.lang.Double.
Now, this seems to be less about the field itself and more to do with related components - this only happens on a field which has a foreign key constraint linking it to an integer field somewhere else.
Basic example of the kind of thing I'm going for:
Template.cfc
component persistent="true" table="template"{
property name="id" type="numeric" sqltype="integer" column="templateID" fieldtype="id" generator="identity";
property name="userID" type="numeric" sqltype="integer" fkcolumn="userID" fieldtype="many-to-one" cfc="User";
property name="lastModified" type="date" sqltype="timestamp" column="lastModified";
}
User.cfc
component persistent="true" table="user"{
property name="id" type="numeric" sqltype="integer" column="userID" fieldtype="id" generator="identity";
property name="username" type="string" sqltype="nvarchar" column="username";
property name="password" type="string" sqltype="nvarchar" column="password";
}
The problem occurs when flushing the ORM having updated template.userID.
Things I've tried
Contacting Adobe CF Support (we have an enterprise licence with platinum support, but in a month they haven't been able to give me a solution or even any information beyond "it's not working?")
Adding the ormtype attribute to identity fields (and then foreign key fields when that didn't work)
Changing the sqltype property (which I now believe is only for table creation which we never needed anyway since the database was already in place)
Converting the variable using various combinations of the following functions:
NumberFormat( var ) - documentation says it returns 'A formatted number value', actually returns a java.lang.String
LSParseNumber( var )- returns a double
Int( var ) - This one's great: documentation says it returns an integer, as a string. Actually returns a java.lang.Double
Val( var ) - returns a double
javaCast( 'int', var ) - returns an integer, which throws the same error
Setting the elementtype attribute on the property (both ends)
Relaxing the validate attribute on the property (both ends) to 'numeric'
I suspect this may be to do with a combination of Hibernate and CF, rather than just CF, and dispite it's javascript-reminiscent quirks, I still love it.
Environment
Windows Server 2012 R2
ColdFusion 2016 (Enterprise)
SQL Server
TL:DR;
Pass the entity, not the ID.
A foreign key property in CF ORM referencing persistent entity Foo is of type Foo and not int.
More detail
After all this time, Adobe passed me around a few people until I landed on an engineer who knew what he was talking about. It turns out the problem is not so much with the ORM engine (Hibernate) not recognising the integer as an integer, but if you have a foreign key which references another persistent entity, then you must pass the entity and not the ID.
Example (in context of the question)
First, I've removed the type and sqltype values from the question, since the former can be retrieved by CF inspecting the DB (which in my case is fine, but you may have to explicitly set it, especially if you've turned off useDBforMapping in Application.cfc).
Second, I've renamed the userID property in the Template component to user, as it may help those that don't immediately understand what I said above about 'passing the entity' to visualise it better.
Template.cfc
component persistent="true" table="template"{
property name="id" column="templateID" fieldtype="id" generator="identity";
property name="user" fkcolumn="userID" fieldtype="many-to-one" cfc="User";
property name="lastModified" column="lastModified";
}
User.cfc
component persistent="true" table="user"{
property name="id" column="userID" fieldtype="id" generator="identity";
property name="username" column="username";
property name="password" column="password";
}
So, lets say you know the ID of the user who is associated with this template (maybe they're the creator, for example). What you have to do is, not pass the ID to the user property, but rather create a User component, then pass that.
index.cfm
userID = 4; // Example user ID, which we got from somewhere earlier in the code
templateID = 20; // Example template ID, which we got from somewhere earlier in the code
// Create template entity (loading by primary key)
template = EntityLoadByPK( 'Template', templateID );
// To set the user in the Template entity, we must pass a User entity
user = EntityLoadByPK( 'User', userID );
// Only then can we successfully update the template's foreign key property
template.setUser( user );
EntitySave( template );
// Line below is not usually needed, but it forces DB interaction so it's
// useful in the context of this example
ORMFlush();
Hope this helps anyone else who happens across the same confusion.
JC

How to force composite indexes to appear in Google Cloud?

Ok, see this picture in Google Cloud:
It said "Below are the composite indexes for this application. These indexes are managed in your app's index configuration file."
And see this following code:
public static long getPropertyMaxIDStronglyConsistent(String entityName, String propertyName, Key parentKey){
// Order alphabetically by property name:
//Key parentKey=KeyFactory.createKey(parentEntityName, parentName);
Query q = new Query(entityName, parentKey).setAncestor(parentKey)
.addSort(propertyName, SortDirection.DESCENDING);
//List<Entity> results = datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
List<Entity> results = datastore.prepare(q)
.asList(FetchOptions.Builder.withLimit(5));
if(results.size()>0){
Entity e=results.get(0);
long maxID=(Long)e.getProperty(propertyName);
return maxID;
}
else{
return 0;
}
}
Suppose that we are running this function1 getPropertyMaxIDStronglyConsistent("EnglishClass", "ClassNo", KeyFactory.createKey("EnglishClassParent", "EnglishClassParentName")).
What I found out that, the function1 is not gonna work if the kind "EnglishClass" does not appear in Indexes Table with "serving" status.
I didn't know what I did but after I was struggling for a few hours then suddenly the Index "EnglishClass" appeared. When the "EnglishClass" appeared with "serving" status, the app can work as normal without any problem.
My questions are
What are composite indexes?
Why didn't it appear immediately after running the function1?
What does "serving" status mean?
How to force composite indexes to appear in Google Cloud?
Extra:
In the datastore-indexes-auto.xml I have
<datastore-indexes autoGenerate="true">
<datastore-index kind="EnglishClass" ancestor="true" source="auto">
<property name="ClassNo" direction="desc"/>
</datastore-index>
</datastore-indexes>
But it still did not work
Indexes for the App Engine datastore are described in these docs and these docs(Java 7, but the principles are the same for Java 8).
A composite index is an index that comprises of more than one property of a model: for example an index that sorts a model by Model.name, then Model.creationDate. Composite indexes are used by queries that need to access datastore records in the order described by the query.
Some indexes must be declared in the datastore-indexes.xml file - see here
Serving status means that the index is ready for use; when an index is first uploaded App Engine must build the index, and until the index is built queries that use the building index will throw an exception. So it can be helpful to update indexes before deploying the code that requires them.
Configure your app to automatically configure indexes.

What is the best way to import an XML string into a SQL Server table

I am working with a 3rd product called JPOS and it has an XMLPackager whereby I get a string from this packager that contains a record in an XML format such as:
<MACHINE><B000>STRING_VALUE</B000><B002>STRING_VALUE</B002><B003>STRING_VALUE</B003><B004>STRING_VALUE</B004><B007>STRING_VALUE</B007><B011>STRING_VALUE</B011><B012>STRING_VALUE</B012><B013>STRING_VALUE</B013><B015>STRING_VALUE</B015><B018>STRING_VALUE</B018><B028>STRING_VALUE</B028><B032>STRING_VALUE</B032><B035>STRING_VALUE</B035><B037>STRING_VALUE</B037><B039>STRING_VALUE</B039><B041>STRING_VALUE</B041><B043>STRING_VALUE</B043><B048>STRING_VALUE</B048><B049>STRING_VALUE</B049><B058>STRING_VALUE</B058><B061>STRING_VALUE</B061><B063>STRING_VALUE</B063><B127>STRING_VALUE</B127></MACHINE>
I have a SQL server table that contains a column for each of the listed. Not that it matters but I could potentially have thru defined with specific STRING_VALUEs. I'm not sure what is the best way to go about this in Java. My understanding is that SQL Server can take an XML string (not document) and do an insert. Is it best to parse each value and then put into a list that populate each value into? This is the first time I've used an XML file and therefore trying to get some help/direction.
Thanks.
Sorry, one of my colleagues was able to help and provide a quick answer. I'll try it from my Java code and it looks like it should work great. Thanks anyway.
Here is the SP that she created whereby I can pass in my XML string and bit value:
CREATE PROCEDURE [dbo].[sbssp_InsertArchivedMessages]
(
#doc varchar(max),
#fromTo bit
)
AS
BEGIN
DECLARE #idoc int, #lastId int
EXEC sp_xml_preparedocument #idoc OUTPUT, #doc
INSERT INTO [dbo].[tblArchivedMessages]
SELECT * FROM OPENXML(#idoc, '/MACHINE', 2) WITH [dbo].[tblArchivedMessages]
SET #lastId = (SELECT IDENT_CURRENT('tblArchivedMessages'))
UPDATE [dbo].[tblArchivedMessages]
SET FromToMach = #fromTo
WHERE ID = #lastId
END
GO
Regards.

HQL search within child SET with IN keyword

i really can not find enough documentation on hibernate IN keyword, when applied on search within a collection of some object. I have strange problem, I have a hql query:
FROM Contact co, IN (co.categories)categories WHERE categories.name = ?
In i was expecting list of Contacts ofcourse. But something is wrong with it, because it is not returning list of Contact objects, but list of Object[]????? Is it syntax or this is totally wrong??
Here are mapping parts:
<set lazy="false" name="categories" table="ContactCategory">
<key column="id" foreign-key="fk_contact_category" />
<many-to-many class="Category" column="catid"
foreign-key="fk_contact_category2" />
</set>
<class name="Category">
<id column="catid" name="Id" type="long">
<generator class="sequence" />
</id>
<property length="50" name="name" type="string" />
</class>
Important thing to mention: This query is made with the query builder. This is printout of one of generated queries where its failing. Very weird is that - i am getting the correct number of objects in this list, I check the database and number is correct with given parameters, but I dont get Contact objects, but some Object arrays in the List.
Appreciate all the help
You need to add SELECT co
so that your Query is SELECT co FROM Contact co, IN (co.categories)categories WHERE categories.name = ?
The SELECT co is necessary, to tell Hibernate which one item it should return per result set line.
SELECT co FROM Contact co LEFT JOIN co.categories cat WHERE cat.name = ?
I have seen the IN keyword only in the Where - clause so far. In Stuff like this,
FROM catagories cat WHERE cat.name IN ('HALLO', 'WORLD')
I dont like answering my question, without really understanding why this SELECT is neccessary, but this works as a charm. If someone explains me reasoning, I would be happy to vote his answer.
**SELECT co** FROM Contact co, IN (co.categories)categories WHERE categories.name = ?
Thank you all
Julia, try printing the class and value of each object in the array of your original query like this:
List<Object[]> results = // code to fetch your query ;
// just the first, or you can print every entry with a outer loop
Object[] firstObject = results.get(0);
for (Object o : firstObject) {
System.out.println(o.getClass() + " - " + o);
}
My guess is that hibernate is inferring either a Contact object and a separate Category list or is bringing columns returned from the query as primitive wrappers. Anyway, the problem seems to be that Hibernate could not figure out what you were expecting to fetch from the the list of columns that were returned by the DBMS. In the second query you narrowed it down to an alias of the specific type you wanted, so everything worked as expected.
This worked for me in Grails 2.1.4 HQL
Task.executeQuery("
select task from Task task join task.tags tag where tag.name = 'duplicate' ")
assuming the entity Task.groovy has
static hasMany = [tags: Tag]

Google App Engine Error: No matching index found. (Java)

I am writing a query but it always says "No matching index found". I don't know why. My code is as below:
Query query = pm.newQuery(Classified.class);
query.setFilter("emp_Id == emp");
query.setOrdering("upload_date desc");
query.declareParameters("String emp");
List<Classified> results = (List<Classified>)query.execute(session.getAttribute("emp_Id").toString());
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="true">
<datastore-index kind="Classified" ancestor="false">
<property name="emp_Id" direction="asc" />
<property name="category" direction="asc" />
<property name="upload_date" direction="desc" />
</datastore-index>
</datastore-indexes>
I have added the above index, but it did not help.
I believe you need to configure a Datastore Index. There's probably one already generated for you in Eclipse at WEB-INF/appengine-generated/datastore-indexes-auto.xml that you just need to copy to WEB-INF/datastore-indexes.xml and deploy again.
Because this needs to be somewhere on the internet...
I kicked myself when I found this out
The error is you do not have a index matching what the query would like to perform. You can have multiple indexes for each entity.
In the Logcat, error, it will tell you exactly what index to set and what order the elements need to be.
ie, if the error says it wants (it wont be nicely formatted):
<datastore-index kind="Classified" ancestor="false">
<property name="category" direction="desc" />
<property name="upload_date" direction="desc" />
</datastore-index>
then Project -> war -> WEB-INF -> appengine-generated -> datastore-indexes-auto.xml and add exactly that. Then, redeploy the project.
Next go into your Google Cloud Console and look at Datastore -> indexes. It should say that the index is being prepared (This goes quicker if you can kill all apps connected and shut down the instance in the console).
Once this has moved into the list of other indexes, rerun the your application and it wont error out with regards to the index anymore.
Go get it Gentlemen/Ladies
The index you define must hold all possible results in the order they will be returned. Your query asks for a particular emp_Id, ordered by upload_date, but your index is ordered primarily by category.
Try removing the category line from your index definition, or swapping the order of category and upload_date, to make upload_date the primary sort order for the index. If another part of your code relies on the category line, you may have to make two separate indices (which incurs some computational cost).
Edit: see comment below by Nick Johnson re. extra parameters.
I am running into this issue at the moment when doing a single property query such as:
const query = datastore
.createQuery('Emailing_dev')
.filter('status', '=', 'Scheduled')
In my case, I should not be getting any errors, however I get Error 9: No matching index found.
If I defined the single property index twice in the yaml, it works:
indexes:
- kind: Emailing_dev
properties:
- name: status
- name: status
but this for sure must be a bug..!!

Categories