Modify map table name in hibernate - java

Here's my class:
#Entity (name = "Client")
public abstract class MyClient
{
private Map<String, String> _properties;
}
Hiberate map my properties object into a class named "MyClient_properties".
How can I modify it so it will be mapped to "Client_properties"?
Thanks

Interestingly I thought that is supposed to be the default. Pretty sure the default naming feature is supposed to take the #Entity#name value rather than the class name if it is supplied.
Anyway, to explicitly name the collection table you'd use (oddly enough) the JPA #CollectionTable annotation:
#CollectionTable( name="Client_properties" )
private Map<String, String> _properties;

Related

Map Table Record into JPA Entity

I have two classes TableNameA and TableNameB inside two different dependencies DependencyA and DependencyB representing tables table_name_a and table_name_b with fields described below.
TableName: table_name_a
Field's Name: field_name_p, field_name_q, field.
TableName: table_name_b
Field's Name: field_name_r, field_name_s.
#Entity
#Table(name = "table_name_a")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TableNameA{
#Id
private int field;
private int fieldNameP;
private int fieldNameQ;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TableNameB{
#Column(name = "field_name_r")
private int fieldNameR;
#Column(name = "field_name_s")
private int fieldNameS;
}
log.info(dslContext.selectFrom(TableNameA.TABLE_NAME_A)
.limit(4)
.fetch()
.into(dependencyA.TableNameA.class).toString());
log.info(dslContext.selectFrom(TableNameB.TABLE_NAME_B)
.limit(4)
.fetch()
.into(dependencyB.TableNameB.class).toString());
I am using jooq as explained above and I want to map table_name_a and table_name_b record into TableNameA and TableNameB class but in the object of TableNameA only 'field' member variable is mapped properly and rest of member variable's fieldNameP, fieldNameP are mapped to null rather than corresponding values in column of table and TableNameB is mapped properly.
The issue here is member variable's fieldNameP, fieldNameP are mapped to null rather than corresponding values in column of table
And One more condition i can't edit TableNameA and TableNameB classes instead I have to write my own models to map if i don't get solution for this.
What you describe is a known issue in jOOQ: https://github.com/jOOQ/jOOQ/issues/4586. Also the fields without a #Column annotation should be mapped, unless they are annotated as #Transient. The reason field gets mapped properly is that it has an #Id annotation.
For the time being I suggest you vote for the linked GitHub issue so that the issue gets attention and can be properly prioritized.

Spring data #Transient in abstract class

I have a strategy pattern implemented with an abstract class called presentation
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#Type( value=PiePresentation.class, name="PIE"),
#Type( value=BarPresentation.class, name="BAR")})
public abstract class Presentation {
String id;
List<? extends DetailResponse> data = new ArrayList();
String[] variables;
Map<String, Object> configurations;
#Transient
protected ExecutionState state;
}
And two sub classes, here's one of them
public class PiePresentation extends Presentation{
#Transient
private List<Segment> response;
}
This classes are fields of another class that is stored into a mongo collection.
The problem is that spring data is storing the state field of the Presentation class, is like in inheritance the #Transient annotation is being ignored.
Your code looks good to me.
Are you sure that you are using the correct #Transient annotation?
It must be imported from the package org.springframework.data.annotation.
Don't use the javax persistence one.
Moreover be sure to use MappingMongoConverter. Annotation based mapping only works if you're using the MappingMongoConverter as backing converter for MongoTemplate. If you're not configuring the converter a SimpleMongoConverter will be used by default that simply serializes objects into Mongo without taking a look at any meta information whatsoever.

MongoDB document's #Id to be a property of an HashMap?

I have a class which it's only field is an HashMap.
Is it possible to define the #Id of the class to be one of the keys of the HashMap? (which always exists there)
Thanks!
If you have a Class that contains only an HashMap don't define a Class because it not make any sense, instead convert your query result directly in an Map likes Map<String, Object> dbCursor = mongoTemplate.getCollection("articles").find(query.getQueryObject(), Map.class).first();
I suggest you to use the Class in order to define your object, maybe you can use something like
public class Foo {
#Id
private String id;
private Map<String, Object> data;
private Map<String, Object> metadata;
}
in order to maintain flexibility

How to save and query dynamic fields in Spring Data MongoDB?

I'm on Spring boot 1.4.x branch and Spring Data MongoDB.
I want to extend a Pojo from HashMap to give it the possibility to save new properties dynamically.
I know I can create a Map<String, Object> properties in the Entry class to save inside it my dynamics values but I don't want to have an inner structure. My goal is to have all fields at the root's entry class to serialize it like that:
{
"id":"12334234234",
"dynamicField1": "dynamicValue1",
"dynamicField2": "dynamicValue2"
}
So I created this Entry class:
#Document
public class Entry extends HashMap<String, Object> {
#Id
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
And the repository like this:
public interface EntryRepository extends MongoRepository<Entry, String> {
}
When I launch my app I have this error:
Error creating bean with name 'entryRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.model.MappingException: Could not lookup mapping metadata for domain class java.util.HashMap!
Any idea?
TL; DR;
Do not use Java collection/map types as a base class for your entities.
Repositories are not the right tool for your requirement.
Use DBObject with MongoTemplate if you need dynamic top-level properties.
Explanation
Spring Data Repositories are repositories in the DDD sense acting as persistence gateway for your well-defined aggregates. They inspect domain classes to derive the appropriate queries. Spring Data excludes collection and map types from entity analysis, and that's why extending your entity from a Map fails.
Repository query methods for dynamic properties are possible, but it's not the primary use case. You would have to use SpEL queries to express your query:
public interface EntryRepository extends MongoRepository<Entry, String> {
#Query("{ ?0 : ?1 }")
Entry findByDynamicField(String field, Object value);
}
This method does not give you any type safety regarding the predicate value and only an ugly alias for a proper, individual query.
Rather use DBObject with MongoTemplate and its query methods directly:
List<DBObject> result = template.find(new Query(Criteria.where("your_dynamic_field")
.is(theQueryValue)), DBObject.class);
DBObject is a Map that gives you full access to properties without enforcing a pre-defined structure. You can create, read, update and delete DBObjects objects via the Template API.
A last thing
You can declare dynamic properties on a nested level using a Map, if your aggregate root declares some static properties:
#Document
public class Data {
#Id
private String id;
private Map<String, Object> details;
}
Here we can achieve using JSONObject
The entity will be like this
#Document
public class Data {
#Id
private String id;
private JSONObject details;
//getters and setters
}
The POJO will be like this
public class DataDTO {
private String id;
private JSONObject details;
//getters and setters
}
In service
Data formData = new Data();
JSONObject details = dataDTO.getDetails();
details.put("dynamicField1", "dynamicValue1");
details.put("dynamicField2", "dynamicValue2");
formData.setDetails(details);
mongoTemplate.save(formData );
i have done as per my business,refer this code and do it yours. Is this helpful?

How to map an attribute like Map<Class, AbstractEntity> with hibernate?

Is there any possibility with Hibernate to do the following entity structure?
#Entity
public class Person {
#OneToMany
private Map<Class<? extends PersonRole>, PersonRole> personRoles;
public <T extends PersonRole> T getRole(Class<T> roleClass) {
return roleClass.cast(roles.get(roleClass));
}
}
#Entity
public abstract class PersonRole {
#ManyToOne
private Person person;
}
Basically Hibernate can persist this mapped entity but it is not possible to load it anymore from the database with the following exception:
Exception in thread "main" org.hibernate.HibernateException: null index column for collection: de.his.cs.sys.hibernate.Person.roles
at org.hibernate.persister.collection.AbstractCollectionPersister.readIndex(AbstractCollectionPersister.java:822)
at org.hibernate.collection.internal.PersistentMap.readFrom(PersistentMap.java:277)
at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1189)
at org.hibernate.loader.Loader.readCollectionElements(Loader.java:804)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:655)
at org.hibernate.loader.Loader.doQuery(Loader.java:854)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:293)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:263)
at org.hibernate.loader.Loader.loadCollection(Loader.java:2094)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:61)
A workaround could be using a "simple" collection and filling the map with an interceptor, but I hope for a possibility achieving this without additional infrastructure.
it is possible implementingh a Hibernate UserType which maps the class to a string and back
#OneToMany
#MapKey(name = "className" type=#Type(type="namespace.classToNameUserType"))
private Map<Class<? extends PersonRole>, PersonRole> personRoles;
see here for an example UserType
The problem basically seems to me, that hibernate needs to rely on a persistent attribute for a map key. Therefore the solution adds a new attribute to the abstract class RersonRole:
private Class<?> className = this.getClass();
Then it is possible to refer to it in the #MapKey annotation in the class Person:
#OneToMany
#MapKey(name = "className")
private Map<Class<? extends PersonRole>, PersonRole> personRoles;
With this mapping hibernate can now fill the Map without further infrastructure.
This from my point of view mostly elegant solution has the drawback of adding a persistent attribute, which is only needed because of hibernate (If I get the root cause of the problem right).

Categories

Resources