I would like to get objects ResponsableEntity by id from the Database where they are saved. I use Spring-boot and hibernate for the first time and the slouches on other topics don't work in my project
Here are my code :
ResponsableEntity :
#Entity
#Table(name = "responsable")
public class ResponsableEntity {
/**
* Id of the responsable
*/
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* First name of the responsable
*/
#Column(nullable=false)
private String firstName;
/**
* Lst name of the responsable
*/
#Column(nullable=false)
private String lastName;
/**
* Last latitude of the responsable position
*/
private Double latitude;
/**
* Last longitude of the responsable position
*/
private Double longitude;
/**
* All getters and setters [...]
*/
}
ResponsableDBRepository :
#Repository
public interface ResponsableDBRepository extends CrudRepository<ResponsableEntity, Long> {
}
ResponsableController (REST) :
#RestController
#RequestMapping("/responsable")
public class ResponsableController {
/**
* CRUD Repository atribut needed for the methods below
*/
private final ResponsableDBRepository responsableDBRepository;
private final ResponsableStatDBRepository responsableStatDBRepository;
/**
* Constructor
*
* #param responsableDBRepository CRUD repository for ResponsableEntity
* #param responsableStatDBRepository CRUD repository for ResponsableStatEntity
*/
#Autowired
public ResponsableController(ResponsableDBRepository responsableDBRepository, ResponsableStatDBRepository responsableStatDBRepository){
this.responsableDBRepository = responsableDBRepository;
this.responsableStatDBRepository = responsableStatDBRepository;
}
#GetMapping(path = "/get")
public #ResponseBody String getAllResponsable(){
//get object with id given
return "Returned";
}
}
I'd like that when we call this request, the entity is load from the database and an object ResponsableEntity is created with the infos saved in the database. I already tried most of the answer I found on other topics but most of the time my IDE told me he can't find the class required and it seems to be "default" classes from Hibernate and Spring
Thank you in advance for your answer !
Use this:-
ResponsableEntity responsableEntity = responsableDBRepository.findById(id);
We are facing a strange problem occurring within our application using eclipselink. We built a multi-tenancy application which keeps several tenants within one table, separated by a tenancy row. The tenant and a separate entityid form the composite key for each entry. We configured the shared cache and everything works well for most of the time. However, sooner or later while using the application, we face situations where eager loading of related entities does not always work properly. The problem is shown in the following example:
The application loads macroallocations by the id of another entity:
#Entity
#Multitenant(value=MultitenantType.SINGLE_TABLE)
#TenantDiscriminatorColumn(name = DatabaseBindingIds.MACROALLOCATION_TENANT, contextProperty = MULTITENANT_PROPERTY_DEFAULT, primaryKey = true)
#Cache(type=CacheType.SOFT,size=100000)
public class MacroAllocation extends ReadWriteRecord {
/**
* The entity id of this macroallocation.
*/
#Id
#Column(name=DatabaseBindingIds.MACROALLOCATION_ID)
private String entityId;
/**
* The phase this macroallocation belongs to.
*/
#ManyToOne(fetch=FetchType.EAGER, optional=false)
//#BatchFetch(BatchFetchType.JOIN)
#JoinColumn(name=DatabaseBindingIds.MACROALLOCATION_PHASE_ID,referencedColumnName=DatabaseBindingIds.PHASE_ID, insertable=true, updatable=true)
private Phase phase;
/**
* The resource this macroallocation is assigned to.
*/
#ManyToOne(fetch=FetchType.EAGER, optional=false)
//#BatchFetch(BatchFetchType.JOIN)
#JoinColumn(name=DatabaseBindingIds.MACROALLOCATION_RESOURCE_ID, referencedColumnName=DatabaseBindingIds.RESOURCE_ID, insertable=true, updatable=true)
private Resource resource;
/**
* The duration of the allocation.
*/
#Column
#Convert(converter = DurationConverter.class)
private Duration duration;
/**
* Get the macroallocation id.
* #exception IllegalStateException EntityId can never be null.
*/
#Override
public String getId() {
if(entityId == null){
throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
}
return entityId;
}
/**
* Set the full id of this macroallocation.
* #exception IllegalStateException EntityId can never be null.
*/
#Override
public void setId(String entityId) {
markNew();
this.entityId = entityId;
if(entityId == null){
throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
}
}
/**
* Get the phase to which the macroallocation belongs.
* #exception IllegalStateException Phase can never be null.
*/
public Phase getPhase() {
if(phase == null){
throw new IllegalStateException("[Constraint violation] phase can not be null in " + this.getClass().getSimpleName());
}
return phase;
}
/**
* Set the phase to which the macroallocation belongs.
* #exception IllegalStateException Phase can never be null.
*/
public void setPhase(Phase x) {
phase = x;
if(phase == null){
throw new IllegalStateException("[Constraint violation] phase can not be null in " + this.getClass().getSimpleName());
}
}
/**
* Get the resource this macroallocation is assigned to.
* #exception IllegalStateException Resource can never be null.
*/
public Resource getResource() {
if(resource == null){
throw new IllegalStateException("[Constraint violation] resource can not be null in " + this.getClass().getSimpleName());
}
return resource;
}
/**
* Set the resource this macroallocation is assigned to.
* #exception IllegalStateException Resource can never be null.
*/
public void setResource(Resource x) {
resource = x;
if(resource == null){
throw new IllegalStateException("[Constraint violation] resource can not be null in " + this.getClass().getSimpleName());
}
}
/**
* Get the duration of this macroallocation.
* #return duration - can be null.
*/
public Duration getDuration() {
return duration;
}
/**
* Set the duration of this macroallocation.
* #param duration - can be null.
*/
public void setDuration(Duration x) {
duration = x;
}
}
To populate our application layer object based on the database layer entities, we usually get more information from related entities the following way:
macroAllocation.getPhase().getScenario().getProject().getId()
The phase should be eagerly loaded with the macroallocation and the scenario should be eagerly loaded as can be seen in the definition of the phase below:
#Entity
#Multitenant(value=MultitenantType.SINGLE_TABLE)
#TenantDiscriminatorColumn(name = DatabaseBindingIds.PHASE_TENANT, contextProperty = MULTITENANT_PROPERTY_DEFAULT, primaryKey = true)
#Cache(type=CacheType.SOFT,size=10000)
public class Phase extends ReadWriteRecord {
/**
* The entity id of this phase.
*/
#Id
#Column(name=DatabaseBindingIds.PHASE_ID)
private String entityId;
#OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
#BatchFetch(BatchFetchType.JOIN)
#JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.PROPERTYSET_ID, insertable=false, updatable=false)
private PropertySet propertySet;
#OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
#BatchFetch(BatchFetchType.JOIN)
#JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.LOGSET_ID, insertable=false, updatable=false)
private LogSet logSet;
#OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
#BatchFetch(BatchFetchType.JOIN)
#JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.COSTSSET_ID, insertable=false, updatable=false)
private CostsSet costsSet;
#OneToOne(fetch=FetchType.LAZY, cascade= CascadeType.PERSIST) // one to one mappings are directly mapped using the phase primary keys
#BatchFetch(BatchFetchType.JOIN)
#JoinColumn(name=DatabaseBindingIds.PHASE_ID, referencedColumnName=DatabaseBindingIds.TODOSET_ID, insertable=false, updatable=false)
private TodoSet todoSet;
#ManyToOne(fetch=FetchType.EAGER, optional=false)
#JoinColumn(name=DatabaseBindingIds.PHASE_SCENARIO_ID, referencedColumnName=DatabaseBindingIds.SCENARIO_ID, insertable=true, updatable=true)
private Scenario scenario;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name=DatabaseBindingIds.PHASE_PARENTPHASE_ID, referencedColumnName=DatabaseBindingIds.PHASE_ID, insertable=true, updatable=true)
private Phase parentPhase;
#Column
private Double sortIndex;
#Column
private String name;
#Column
private String description;
#Column
private String imageUrl;
#Column
#Convert(converter = DurationConverter.class)
private Duration budget;
#Column
#Convert(converter = DurationConverter.class)
private Duration planned;
#Column
#Convert(converter = PointInTimeConverter.class)
private PointInTime.Utc beg;
#Column//(name="\"End\"") // If you think you want to add this, check first why they are not escaped by the EclipseLink SessionCustomizer
#Convert(converter = PointInTimeConverter.class)
private PointInTime.Utc end;
#Column
private Boolean fixed;
#Column
private Integer progress;
#Column
private Boolean autoProgress;
#Column
private String costCenter;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name=DatabaseBindingIds.PHASE_OWNER_ID, referencedColumnName=DatabaseBindingIds.RESOURCE_ID, insertable=true, updatable=true)
private Resource owner;
#Column
private String color;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name=DatabaseBindingIds.PHASE_REQUIRED_SKILL_ID, referencedColumnName=DatabaseBindingIds.RESOURCE_ID, insertable=true, updatable=true)
private Resource requiredSkill;
#OneToMany(mappedBy="fromPhase", fetch=FetchType.LAZY)
private List<PhaseDependency> forwardDependencies;
#OneToMany(mappedBy="toPhase", fetch=FetchType.LAZY)
private List<PhaseDependency> reverseDependencies;
/**
* Get the phase id.
* #exception IllegalStateException EntityId can never be null.
*/
#Override
public String getId() {
if(entityId == null){
throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
}
return entityId;
}
/**
* Set the full id of this phase.
* #exception IllegalStateException EntityId can never be null.
*/
#Override
public void setId(String entityId) {
markNew();
this.entityId = entityId;
if(entityId == null){
throw new IllegalStateException("[Constraint violation] entityId can not be null in " + this.getClass().getSimpleName());
}
propertySet = new PropertySet();
propertySet.setId(entityId);
logSet = new LogSet();
logSet.setId(entityId);
costsSet = new CostsSet();
costsSet.setId(entityId);
todoSet = new TodoSet();
todoSet.setId(entityId);
}
/**
* Get the property set of the phase.
* #exception IllegalStateException propertySet can never be null.
*/
public PropertySet getPropertySet() {
if(propertySet == null){
throw new IllegalStateException("[Constraint violation] propertySet can not be null in " + this.getClass().getSimpleName());
}
return propertySet;
}
/**
* Get the log set of the phase.
* #exception IllegalStateException logSet can never be null.
*/
public LogSet getLogSet() {
if(logSet == null){
throw new IllegalStateException("[Constraint violation] logSet can not be null in " + this.getClass().getSimpleName());
}
return logSet;
}
/**
* Get the costs set of the phase.
* #exception IllegalStateException costsSet can never be null.
*/
public CostsSet getCostsSet() {
if(costsSet == null){
throw new IllegalStateException("[Constraint violation] costsSet can not be null in " + this.getClass().getSimpleName());
}
return costsSet;
}
/**
* Get the todo set of the phase.
* #exception IllegalStateException todoSet can never be null.
*/
public TodoSet getTodoSet() {
if(todoSet == null){
throw new IllegalStateException("[Constraint violation] todoSet can not be null in " + this.getClass().getSimpleName());
}
return todoSet;
}
/**
* Get the scenario of the phase.
* #exception IllegalStateException scenario can never be null.
*/
public Scenario getScenario() {
if(scenario == null){
throw new IllegalStateException("[Constraint violation] scenario can not be null in " + this.getClass().getSimpleName());
}
return scenario;
}
/**
* Set the scenario of the phase.
* #exception IllegalStateException scenario can never be null.
*/
public void setScenario(Scenario x) {
scenario = x;
if(scenario == null){
throw new IllegalStateException("[Constraint violation] scenario can not be null in " + this.getClass().getSimpleName());
}
}
/**
* Get the parent phase of this phase.
* #return parentPhase - can be null.
*/
public Phase getParentPhase() {
return parentPhase;
}
/**
* Set the parent phase of this phase.
* #return parentPhase - can be null.
*/
public void setParentPhase(Phase x) {
parentPhase = x;
}
/**
* Get the sort index of the phase.
* #return
*/
public double getSortIndex() {
return sortIndex == null ? 0.0 : sortIndex;
}
/**
* Set the sort index of the phase.
* #param x
*/
public void setSortIndex(double x) {
sortIndex = x;
}
/**
* Get the name of the phase.
* #return name - can be null.
*/
public String getName() {
return name;
}
/**
* Set the name of this phase.
* #param name - can be null.
*/
public void setName(String x) {
name = x;
}
/**
* Get the description of the phase.
* #return description - can be null.
*/
public String getDescription() {
return description;
}
/**
* Set the description of this phase.
* #param description - can be null.
*/
public void setDescription(String x) {
description = x;
}
/**
* Get the image url of the phase.
* #return imageUrl - can be null.
*/
public String getImageUrl() {
return imageUrl;
}
/**
* Set the imag url of this phase.
* #param imageUrl - can be null.
*/
public void setImageUrl(String x) {
imageUrl = x;
}
/**
* Get the budget of the phase.
* #return budget - can be null.
*/
public Duration getBudget() {
return budget;
}
/**
* Set the budget of this phase.
* #param budget - can be null.
*/
public void setBudget(Duration x) {
budget = x;
}
/**
* Get the planned duration of the phase.
* #return planned - can be null.
*/
public Duration getPlanned() {
return planned;
}
/**
* Set the planned duration of this phase.
* #param planned - can be null.
*/
public void setPlanned(Duration x) {
planned = x;
}
/**
* Get the beginning of the phase.
* #return beg - can be null.
*/
public PointInTime.Utc getBeg() {
return beg;
}
/**
* Set the beginning of this phase.
* #param beg - can be null.
*/
public void setBeg(PointInTime.Utc x) {
beg = x;
}
/**
* Get the ending of the phase.
* #return end - can be null.
*/
public PointInTime.Utc getEnd() {
return end;
}
/**
* Set the ending of this phase.
* #param end - can be null.
*/
public void setEnd(PointInTime.Utc x) {
end = x;
}
/**
* Get if the phase is fixed.
* #return
*/
public boolean getFixed() {
return fixed == null ? false : fixed;
}
/**
* Set if the phase is fixed.
* #param x
*/
public void setFixed(boolean x) {
fixed = x;
}
/**
* Get the progress of the phase.
* #return
*/
public int getProgress() {
return progress == null ? 0 : progress;
}
/**
* Set the progress of this phase.
* #param
*/
public void setProgress(int x) {
progress = x;
}
/**
* Get if the phase progresses automatically.
* #exception IllegalStateException autoProgress can never be null.
*/
public boolean getAutoProgress() {
return autoProgress == null ? false : autoProgress;
}
/**
* Get if the phase progresses automatically.
* #exception IllegalStateException autoProgress can never be null.
*/
public void setAutoProgress(boolean x) {
autoProgress = x;
}
... not relevant getters and setters...
}
To get proper exceptions when our problem occurs, we added IllegalStateExceptions being thrown that tell us similarly to the db constraints, that an eager loading constraint has been violated. When the problem occurs, we get:
java.lang.IllegalStateException: [Constraint violation] scenario can not be null in Phase
This means that during the loading of the macroallocation, the scenario was not loaded.
The only workaround we found is by accessing the scenario while the database session is still open, but from our understanding, this should only be necessary to load lazy loaded entity relations. What could the problem be? Below are the macroallocation loading method:
#Override
public List<MacroAllocation> loadMacroAllocationsByResource(String resourceId) throws DataAccessException {
try(DatabaseSession session = new DatabaseSession(tenant)) {
List<MacroAllocation> macroAllocations = session.loadByQuery(MacroAllocation.class,
"SELECT ma FROM MacroAllocation AS ma "
+ "WHERE ma.resource.entityId = ?1 " // with matching primary key in resource
+ "AND ma.deleted = 0", // and not deleted
resourceId);
//Workaround: Some objects are not eagerly fetched in some cases. Here we do that explicitly.
macroAllocations.stream().forEach((m) -> {
session.fetch(m.getPhase().getScenario());
session.fetch(m.getPhase().getScenario().getProject());
});
return macroAllocations;
} catch(RuntimeException e) {
throw new DataAccessException(e);
}
}
and the database session we use within this method:
public final class DatabaseSession implements AutoCloseable {
/**
* Maximum latency in milliseconds for a JPA operation, after which a warning shall be logged.
*/
private static final double MAX_LATENCY = 100.0;
/**
* Maximum duration in milliseconds for a session, after which a warning shall be logged.
*/
private static final double MAX_LATENCY_TOT = 1000.0;
/**
* Our logger, never null.
*/
private static final Logger log = LoggerFactory.getLogger(DatabaseSession.class);
/**
* The factory for creating EntityManager instances, created in initEntityManagerFactory() or in the constructor.
*/
private static String persistenceUnitName;
/**
* The EntityManager instance to access the database, created from the factory in the constructor.
*/
private EntityManager em;
/**
* The time when the instance was created, useful for measure total time of the session.
*/
private final long ttot = System.nanoTime();
/**
* Indicates whether commit() as been called.
*/
private boolean committed;
private String tenant;
private static final Cache<String, EntityManagerFactory> emfs = new Cache<>(tenant -> { // create if absent
synchronized (DatabaseSession.class) {
HashMap<String,String> properties = new HashMap<>();
properties.put(SESSION_NAME, (tenant!=null && tenant != "")?tenant+"-session":"non-tenant-session");
properties.put(MULTITENANT_PROPERTY_DEFAULT, tenant);
if(persistenceUnitName == null){
log.debug("Persistence Unit Name defaults to: default");
persistenceUnitName = "default";
}
return Persistence.createEntityManagerFactory(persistenceUnitName, properties);
}
},
(entityManagerFactory) -> { // on remove
entityManagerFactory.close();
});
/**
* Opens a new non-tenant specific session and begins a new transaction.
*
* Only shared, non-tenant specific entities can be retrieved. Multitenancy entities can not be retrieved using this session. To retrieve tenant specific entities, create a tenant session using <b>new DataSession(tenant)</b>
*/
public DatabaseSession() {
this.tenant = "";
synchronized (DatabaseSession.class) {
emfs.get(tenant);
}
createEntityManager();
}
/**
* Opens a new tenant session and begins a new transaction.
*
* Multitenancy entities can be retrieved using this session.
*/
public DatabaseSession(String tenant) {
if(tenant == null || tenant.equals("")){
log.error("Trying to create a non-tenant database session with tenant specific constructor? Use constructor DatabaseSession() instead.");
tenant = "";
}
this.tenant = tenant;
synchronized (DatabaseSession.class) {
emfs.get(tenant); // creates a new factory in a synchronized manner.
}
createEntityManager();
}
/**
* #note: Should only be called publicly by unit tests.
*/
public void createEntityManager() {
em = emfs.get(tenant).createEntityManager();
em.getTransaction().begin();
}
/**
* Initializes the EntityManagerFactory (optional, useful for testing).
* <p>
* If this method is not called, the EntityManagerFactory is initialized automatically with persistence unit "default" when the first instance is created.
* <p>
* Persistence units are defined in conf/META-INF/persistence.xml.
*
* #param persistenceUnitName
* the name of the persistence unit to be used, must match the XML attribute /persistence/persistence-unit/#name.
*/
public static void initEntityManagerFactory(String pun) {
persistenceUnitName = pun;
}
/**
* Sets up all factories to prevent eclipselink from drop and creating the db.
*
* #note: Should only be called by unit tests.
*/
public void setupEntityManagerFactories(List<String> tenants) {
log.warn("SetupEntityManagerFactories should only be called by Unit tests.");
for(String tenant: tenants){
emfs.get(tenant);
}
}
/**
* Closes the connection to the database completely. For Unit tests, this drops and recreates the database to advance to the next unit test with a fresh one.
*
* #note: Should only be called by unit tests.
*/
public void shutdownDB() {
log.warn("ShutdownDB should only be called by Unit tests.");
em.close();
em = null;
DatabaseSession.emfs.clear(); // closes entity manager factory on close
}
#Override
public void close() {
try {
if (!committed) {
if (em != null) {
em.getTransaction().rollback();
}
}
} finally {
if (committed) {
if (em != null) {
em.close();
}
}
double latency = (System.nanoTime() - ttot) / 1000000.0;
if (latency > MAX_LATENCY_TOT) {
log.warn("Duration of session was " + latency + "ms.");
} else {
log.debug("Duration of session was " + latency + "ms.");
}
}
}
/**
* Commits the transaction, must explicitly be done before the session is closed.
*/
public void commit() {
long t = System.nanoTime();
em.flush();
em.getTransaction().commit();
committed = true;
double latency = (System.nanoTime() - t) / 1000000.0;
if (latency > MAX_LATENCY) {
warn("Latency of commit() was %sms.", latency);
}
}
public <T extends PersistentRecord> List<T> loadAll(Class<T> clazz) {
return loadAll(clazz, true);
}
public <T extends PersistentRecord> List<T> loadAll(Class<T> clazz, boolean filterDeleted) {
log("loadAll(%s)", clazz.getSimpleName());
long t = System.nanoTime();
CriteriaBuilder b = em.getCriteriaBuilder();
CriteriaQuery<T> q = b.createQuery(clazz);
Metamodel m = em.getMetamodel();
EntityType<T> et = m.entity(clazz);
Root<T> r = q.from(clazz);
q.select(r);
if (filterDeleted) {
q.where(b.equal(r.get(et.getAttribute("deleted").getName()), 0));
}
List<T> results = em.createQuery(q).getResultList();
double latency = (System.nanoTime() - t) / 1000000.0;
if (latency > MAX_LATENCY) {
warn("Latency of loadAll(%s) was %sms.", clazz.getSimpleName(), latency);
}
return results;
}
public <T extends PersistentRecord> int count(Class<T> clazz) {
return count(clazz, true);
}
public <T extends PersistentRecord> int count(Class<T> clazz, boolean filterDeleted) {
log("count(%s)", clazz.getSimpleName());
long t = System.nanoTime();
CriteriaBuilder b = em.getCriteriaBuilder();
CriteriaQuery<T> q = b.createQuery(clazz);
Metamodel m = em.getMetamodel();
EntityType<T> et = m.entity(clazz);
Root<T> r = q.from(clazz);
q.select(r);
if (filterDeleted) {
q.where(b.equal(r.get(et.getAttribute("deleted").getName()), 0));
}
List<T> result = em.createQuery(q).getResultList();
double latency = (System.nanoTime() - t) / 1000000.0;
if (latency > MAX_LATENCY) {
warn("Latency of count(%s) was %sms.", clazz.getSimpleName(), latency);
}
return result.size();
}
public <T extends PersistentRecord> T load(Class<T> clazz, String id) {
return load(clazz, id, true);
}
public <T extends PersistentRecord> T load(Class<T> clazz, String id, boolean filterDeleted) {
log("load(%s, %s)", clazz.getSimpleName(), id);
long t = System.nanoTime();
T result = em.find(clazz, id);
if (filterDeleted) {
result = filterDeleted(result);
}
double latency = (System.nanoTime() - t) / 1000000.0;
if (latency > MAX_LATENCY) {
warn("Latency of load(%s, %s) was %sms.", clazz.getSimpleName(), id, latency);
}
return result;
}
public <T extends PersistentRecord> List<T> loadByQuery(Class<T> clazz, String query, Object... params) {
log("loadByQuery(%s, '%s', %s)", clazz.getSimpleName(), query, format(params));
long t = System.nanoTime();
TypedQuery<T> q = em.createQuery(query, clazz);
for (int i = 0; i < params.length; i++) {
q.setParameter(i + 1, params[i]);
}
List<T> result = q.getResultList();
result = filterDeleted(result);
double latency = (System.nanoTime() - t) / 1000000.0;
if (latency > MAX_LATENCY) {
warn("Latency of loadByQuery(%s, '%s', %s) was %sms.", clazz.getSimpleName(), query, format(params), latency);
}
return result;
}
public <T extends PersistentRecord> T loadSingleByQuery(Class<T> clazz, String query, Object... params) {
log("loadSingleByQuery(%s, '%s', %s)", clazz.getSimpleName(), query, format(params));
long t = System.nanoTime();
TypedQuery<T> q = em.createQuery(query, clazz);
for (int i = 0; i < params.length; i++) {
q.setParameter(i + 1, params[i]);
}
List<T> result = q.getResultList();
result = filterDeleted(result);
double latency = (System.nanoTime() - t) / 1000000.0;
if (latency > MAX_LATENCY) {
warn("Latency of loadSingleByQuery(%s, '%s', %s) was %sms.", clazz.getSimpleName(), query, format(params), latency);
}
return result.size() > 0 ? result.get(0) : null;
}
... storing methods not relevant here...
}
I have a column name viewed_by on Firebase server
Test
|
|--viewed_by: 30
On the app I have a POJO class which has the member viewed_by
Test.class has member
private int viewed_by;
In onDataChange function when I receive the data, I get the Test object using the getValue function
Test t = dataSnapshot.getValue(Test.class);
But I get the value as 0 instead of 30.
If I change the field name from viewed_by to viewedBy (both on server and POJO class), I get the expected value (30)
Is it a parsing issue in getValue function? Or the field name are not supposed to have underscores in the name?
Jus figured it out, had to change the function names as well from ViewedBy to Viewed_By for it to work with viewed_by field
/**
*
* #return
* The viewed_by
*/
public int getViewed_By() {
return viewed_by;
}
/**
*
* #param viewed_by
* The viewed_by
*/
public void setViewed_By(int viewed_by) {
this.viewed_by = viewed_by;
}
Another option is to just declare the properties like below-using #PropertyName("property_name") in your model and use your getter and setter just like you like to do.
public class Actor {
#NonNull
#PrimaryKey
#ColumnInfo(name = "profile_id")
#PropertyName("profile_id")
private String profileId;
#ColumnInfo(name = "name")
#PropertyName("name")
private String name;
#PropertyName("profile_id")
public String getProfileId() {
return profileId;
}
#PropertyName("profile_id")
public void setProfileId(String profileId) {
this.profileId = profileId;
}
#PropertyName("name")
public String getName() {
return name;
}
}
Based on an archetype i created a java ee app. There is an included arquillian test that runs fine. it just calls a method on a #Stateless bean that persists an pre-made entity.
now i added some entity with some relations and i wrote a test for them. But on peristing any entity i get
Transaction is required to perform this operation (either use a transaction or extended persistence context)
I think i need to mark the testmethod with #Transactional but it seems not to be in class path.
Manually invoking the transaction on injected EntityManager yields another error.
So how to correctly setup such tests and dependencies.
EDIT As Grzesiek D. suggested here are some details. this is the entity (the one thta links others):
#Entity
public class Booking implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* internal id.
*/
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
/**
* Used for optimistic locking.
*/
#Version
#Column(name = "version")
private int version;
/**
* A booking must have a project related.
*/
#ManyToOne
#JoinColumn(name = "project_id")
#NotNull
private Project project;
/**
* A booking must have an owner.
*/
#ManyToOne
#JoinColumn(name = "user_id")
#NotNull
private User owner;
/**
* A booking always has a start time.
*/
#Column
#NotNull
private Timestamp start;
/**
* A booking always has an end time.
*/
#Column
#NotNull
private Timestamp end;
/**
*
* #return true if start is befor end. false otherwise (if equal or after end).
*/
#AssertTrue(message = "Start must before end.")
public final boolean isStartBeforeEnd() {
return start.compareTo(end) < 0;
}
/**
* #return the id
*/
public final Long getId() {
return id;
}
/**
* #param id
* the id to set
*/
public final void setId(final Long id) {
this.id = id;
}
/**
* #return the version
*/
public final int getVersion() {
return version;
}
/**
* #param version
* the version to set
*/
public final void setVersion(final int version) {
this.version = version;
}
/**
* #return the project
*/
public final Project getProject() {
return project;
}
/**
* #param project
* the project to set
*/
public final void setProject(final Project project) {
this.project = project;
}
/**
* #return the owner
*/
public final User getOwner() {
return owner;
}
/**
* #param owner
* the owner to set
*/
public final void setOwner(final User owner) {
this.owner = owner;
}
/**
* #return the start
*/
public final Timestamp getStart() {
return start;
}
/**
* #param start
* the start to set
*/
public final void setStart(final Timestamp start) {
this.start = start;
}
/**
* #return the end
*/
public final Timestamp getEnd() {
return end;
}
/**
* #param end
* the end to set
*/
public final void setEnd(final Timestamp end) {
this.end = end;
}
//hashCode, equals, toString omitted here
}
Here is the test:
#RunWith(Arquillian.class)
public class BookingTest {
#Deployment
public static Archive<?> createDeployment() {
return ArquillianContainer.addClasses(Resources.class, Booking.class, Project.class, User.class);
}
#Inject
private EntityManager em;
#Test
public void createBooking() {
Booking booking = new Booking();
booking.setStart(new Timestamp(0));
booking.setEnd(new Timestamp(2));
User user = new User();
user.setName("Klaus");
booking.setOwner(user);
Project project = new Project();
project.setName("theOne");
project.setDescription("blub");
booking.setProject(project);
em.persist(booking);
System.out.println("here");
}
}
And here the exception:
javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
I know it will work if i create a #Stateless bean and encapsulate the persist there but i want a direct test of entity's validation and i need a playground to evolve the data model.
In order to have transaction support in Arquillian tests you will need to bring in extension which enables this feature. In your case jta dependency should do the job.
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-transaction-jta</artifactId>
<scope>test</scope>
</dependency>
In addition, if you are using JBoss, you will need to provide its JNDI for UserTranscation, so put following section in your arquillian.xml:
<?xml version="1.0" ?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://jboss.org/schema/arquillian" xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<extension qualifier="transaction">
<property name="manager">java:jboss/UserTransaction</property>
</extension>
</arquillian>
This way you can use #Transactional which comes from this extension's API.
I have something like this(Very simplified version):
public class TransferData implements Serializable{
private Collection[] collections;
private String ID;
public TransferData( Collection[] collections){
this.ID = ID;
this.collections = collections;
}
public String getID(){
return ID;
}
public Collection[] getCollections(){
return collections;
}
}
This is how I usually grab an item:
//Save object in db
ContentValues values = new ContentValues();
values.put("id", td.getID());
However, I am having trouble understanding how to grab an item from a collection/array in a serializable class?
This doesn't make sense:
ContentValues values = new ContentValues();
values.put("collectionitem1", td.getCollections()); ??? //need to index the array, how?
I tried something like this:
for (int i=0; i <= td.getCollections().length; i++) {
System.out.println(i);
}
but strangely only gives me 3 indices instead of 4 indices that I have in my array but it doesn't help me. Also, my array contains strings and integers, so might be hard to index through with a foreach style loop.
Figured it out! I knew it was something about setting up going through the array incorrectly. Here's the solution:
//Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
for (Collection collection : td.getCollections()) {
values.put("reminders", collection.getNumberOfReminders());
}
I see you're using SQLite. It seems to me that you're going about this all wrong. It seems like you need to use Entity Classes:
/**
*
* #author kkennedy
*/
#Entity(name = "TransferData")
#Table(name = "TransferData")
public class TransferData implements Serializable {
#Id
#Basic(optional = false)
#Column(name = "ID", nullable = false, length = 8)
private String ID;
#Basic(optional = false)
#Column(name = "data", nullable = false, length = 8)
private String data;
/**
* Default Constructor
*/
public TransferData() {
}
/**
* Getter
*
* #return
*/
public String getID() {
return ID;
}
/**
* Setter
*
* #param ID
*/
public void setID(String ID) {
this.ID = ID;
}
/**
* Getter
*
* #return
*/
public String getData() {
return data;
}
/**
* Setter
*
* #param data
*/
public void setData(String data) {
this.data = data;
}
}
I'm sure this is not what you would actually use, but by using Entity Classes, the JDBC driver does all the work of actually putting the data into and out of the database. You just enter it into the class and then persist and query the database, as needed.
Not sure if this is the best place to start, but try here for more info: http://docs.oracle.com/javaee/5/tutorial/doc/bnbqw.html