Realm java search Sub model? - java

Really hard to Google this one as I am not entirely sure what it's called.
In my android application I have some Models to return some data from Realm.
Example structure:
Shipment.java :
import java.io.Serializable;
import io.realm.RealmList;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class Shipment extends RealmObject implements Serializable {
#PrimaryKey
public int id;
public Technician technician;
Technician.java :
import io.realm.RealmList;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
public class Technician extends RealmObject {
#PrimaryKey
public int id;
So I am trying to return the shipments that correspond to a technician id.
In my ShipmentsService.java I have this:
public RealmResults<Shipment> forTechnician()
{
Realm realm = Realm.getDefaultInstance();
return realm.where(Shipment.class).contains("technician", "11");
}
Now I know that won't work but I am not sure how I can query based on this relationship.

Link queries. Also, Realm.getDefaultInstance() increments a ref count, so you probably shouldn't let it dangle there like that.
public RealmResults<Shipment> forTechnician(Realm realm) {
return realm.where(Shipment.class).equalTo("technician.id", 11);
}

You can do query like this :
public RealmResults<Shipment> forTechnician()
{
Realm realm = Realm.getDefaultInstance();
return realm.where(Shipment.class).equalTo("technician.id", 11).findAll();
}

Related

Why my Databaseview name appears as non found in my Dao?

I dont know why but Android Studiodoesnt find my DatabaseView. Even if i install others projects
This is the DatabaseView. Its created in a class called LibroDatos.
package com.example.pruebaexamenroom;
import androidx.room.DatabaseView;
#DatabaseView(value = "SELECT libro.id, libro.titulo, libro.autor," +
"libro.idCliente,cliente.name as nombreCliente FROM libro " +
"INNER JOIN Cliente ON libro.idCliente = cliente.idHumano",
viewName = "v_LibroDatos")
public class LibroDatos {
public int id;
public String Titulo;
public String Autor;
public int idCliente;
public String nombreCliente;
}
This is the Dao. Here is where its said that doesnt exist
package com.example.pruebaexamenroom;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Transaction;
import java.util.List;
#Dao
public interface DaoLibro {
#Transaction
#Query("SELECT * FROM v_LibroDatos")
List<LibroDatos> obtenerLibros();
#Insert
void InsertarLibro(Libro...libros);
#Query("UPDATE libro SET titulo =:titulo,autor=:autor WHERE id =:id")
void updateLibro(int id,String titulo,String autor);
#Query("DELETE FROM libro")
void borrarLibro();
}
This is the AppDatabase. Its all declared in here.
package com.example.pruebaexamenroom;
import androidx.room.Database;
import androidx.room.RoomDatabase;
#Database(
entities = {Libro.class, Cliente.class},
views = {LibroDatos.class},
version = 1
)
public abstract class AppDatabase extends RoomDatabase {
public abstract DaoCliente daoCliente();
public abstract DaoLibro daoLibro();
}
I believe that you can just ignore the error and that the project will compile successfully.
If while coding the obtenerLibros Query you type in v for the view you will see that it does know as it prompts to complete e.g.
but then still flags it as an error. However it compiles successfully.
Note if you look at the build log, then it has warnings:-
warning: The query returns some columns [titulo, autor] which are not used by a.a.so75347005javaroomviewnotfound.LibroDatos. You can use #ColumnInfo annotation on the fields to specify the mapping. You can annotate the method with #RewriteQueriesToDropUnusedColumns to direct Room to rewrite your query to avoid fetching unused columns.
a.a.so75347005javaroomviewnotfound.LibroDatos has some fields [Titulo, Autor] which are not returned by the query. If they are not supposed to be read from the result, you can mark them with #Ignore annotation. You can suppress this warning by annotating the method with #SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by the query: id, titulo, autor, idCliente, nombreCliente. - a.a.so75347005javaroomviewnotfound.DaoLibro.obtenerLibros()
So you may wish to
Include the #RewriteQueriesToDropUnusedColumns annotation
Rename the member variables in the LibroDatos class to be lower case.
for 1 :-
#Transaction
#RewriteQueriesToDropUnusedColumns //<<<<<<<<<< ADDED
#Query("SELECT * FROM v_LibroDatos")
List<LibroDatos> obtenerLibros();
for 2 :-
public class LibroDatos {
public int id;
public String titulo; //<<<<<<<<<< was Titulo
public String autor; //<<<<<<<<< was Autor
public int idCliente;
public String nombreCliente;
}

Does findById() actually load data from a JPA repository?

I am a Hibernate beginner. I did a couple of simple tutorials and am trying to write a simple shop backend. Everything works as it should, but I am seeing strange things in my unit tests. When I save an entity, then retrieve it using findById(), it seems that I am simply getting the same object I called save() on, without even retrieving actual values from the database:
package com.bo.learnjava.shop1.repository;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "PRODUCTS")
public class Product {
#Id
#GeneratedValue
#Column(name="ID")
long id;
#Column(name="NAME")
String name = "";
#Column(name="PRICE_CENTS")
int priceCents = 0;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPriceCents() {
return priceCents;
}
public void setPriceCents(int priceCents) {
this.priceCents = priceCents;
}
public long getId() {
return id;
}
}
package com.bo.learnjava.shop1.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ProductRepository extends PagingAndSortingRepository<Product,Long> {
}
package com.bo.learnjava.shop1.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
#DataJpaTest
public class ProductRepositoryTest {
#Autowired
ProductRepository repo;
#Test
void testProductRepository() {
Product p=new Product();
p.setName("Milk");
p.setPriceCents(134);
repo.save(p);
// Modify the value to check that repo.findById() actually retrieves *saved* data
p.setPriceCents(9999);
Optional<Product> productFromRepo=repo.findById(p.getId());**
// I expect productFromRepo to contain the values I called save() with
// (price == 134). But productFromRepo.get() returns exactly the same Java object
// as p (with price == 9999), so no actual data was retrieved from the database - why?
assertTrue(productFromRepo.isPresent());
System.out.println("productFromRepo.priceCents="+productFromRepo.get().getPriceCents()); // Outputs 9999!
assertEquals(134,productFromRepo.get().getPriceCents()); // THIS FAILS!!!
}
}
Why does Hibernate behave like that, and how do I test that stuff I write to the database via Hibernate actually gets retrieved back from the database?
Additionaly to comment about first level cache.
If you are extending JpaRepository you can use
repo.saveAndFlush(p);
or
repo.save(p); repo.flush();
to immediately save data in DB.
After it - repo.findById(p.getId()); will return updated data.

JPA and Java SE - Table not created for Entity class, due to additional convenience methods

I am currently writing a Netbeans platform application for persistence I use JPA 2.1 and eclipse link as provider. I have the following entity class:
import java.util.UUID;
import javafx.beans.property.SimpleStringProperty;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;
/**
*
* #author forell
*/
#Entity
#Access(AccessType.FIELD)
public class MaterialAbc {
#Id
private String id;
//... several additional fields, that all work fine
private String substanceInstances = "";
public MaterialAbc(){
id = UUID.randomUUID().toString();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//.. getters and setters for the omitted fields
public String getSubstanceInstances() {
return substanceInstances;
}
public void setSubstanceInstances(String substanceInstances) {
this.substanceInstances = substanceInstances;
}
/* IF I UNCOMMENT THESE LINES THE DATATABLE IS NOT CREATED ANYMORE
IS THERE A WAY TO SOLVE THIS?
public List<SubstanceInstance2> getSubs() {
List<SubstanceInstance2> subs = new ArrayList<>();
if (!"".equals(substanceInstances)){
List<String> values = Arrays.asList(substanceInstances.split("|"));
values.forEach(value->{
subs.add(SubstanceInstance2.unSerialize(value));
});
}
return subs;
}
public void setSubs(List<SubstanceInstance2> subs) {
substanceInstances = "";
subs.forEach(sub->{
substanceInstances =substanceInstances + sub.serialize() + "|";
});
substanceInstances = substanceInstances.substring(0, substanceInstances.length()-1);
}
*/
As is the class works fine, as soon as I uncomment the two methods at the bottom that "unserialize" an object that is nested in the string substanceInstances, eclipselink is not creating the datatables anymore. Is there a way to solve this, or do need to add an extra layer.
In the meantime I actually found a solution to the problem. It seems eclipselink does not convert the Entity-bean into a table, if there are lambda expressions used in the methods. In the end I converted
values.forEach(value->{
subs.add(SubstanceInstance2.unSerialize(value));
});
into
for (String value:values){
subs.add(SubstanceInstance2.unSerialize(value));
}
And everthing works nicely. As to the reason why, no idea!

session.get() unable to resolve field,argument

I'm totally new to Spring MVC but still trying to understand its methods and its way of referencing things. There's a video tutorial course I'm following.
I'm trying to implement a Model through a class.
ProductDaoImpl.java
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public class ProductDaoImpl implements ProductDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public void addProduct(Product product) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(product);
session.flush();
}
#Override
public Product getProductById(String id) {
Session session = sessionFactory.getCurrentSession();
Product product = (Product) session.get(Product.class.productId);
// unable to resolve the productId on get()
return product;
}
#Override
public List<Product> getAllProducts() {
return null;
}
#Override
public void deleteProduct(String id) {
}
}
ProductDao.java
import java.util.List;
public interface ProductDao {
void addProduct(Product product);
Product getProductById(String id);
List<Product> getAllProducts();
void deleteProduct(String id);
}
Product.java Model
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO) //tells the system that when an instance is put to database, it will be numbered automatically starting from 1
private String productName;
private String productCategory;
private String productDescription;
private double productPrice;
private String productDimension;
private String productStatus;
private int unitInStock;
private String productManufacturer;
private String productId;
}
However, it's unable to resolve the productId argument in
#Override
public Product getProductById(String id) {
Session session = sessionFactory.getCurrentSession();
Product product = (Product) session.get(Product.class.productId);
return product;
}
Is get() method able to access the fields of Product.class?
Is it asking for a field in Product.class.fieldHere?
I don't understand why it can't resolve the productId
I hope you can help.
Thanks.
The expression Product.class.productId doesn't make sense in Java. Product.class is a class literal, meaning that it's a constant value that represents the Product class, an instance of java.lang.Class. Class has no productId field.
Additionally, you should read the Javadoc for the method--it takes two parameters, a Class object (to tell it what sort of thing you're getting) and an ID. Your call should therefore be session.get(Product.class, id), and if you're using Hibernate 5, you don't need to cast to a Product.
All of this is rather moot, however--instead of hand-rolling a DAO targeting Hibernate, use JPA (which provides advantages such as a generic API, eliminating the need for casting) and Spring Data (which will autogenerate this entire DAO for you from nothing but an empty interface declaration). Additionally, you're dealing with topics that can get complicated, and you would do well to go through some exercises to learn core Java before tackling something like ORM.
session.get(Product.class.productId);
That's not valid Java code. get() expects two arguments: the entity class, and the ID of the entity to get. Arguments in Java are separated by a comma.
session.get(Product.class, productId);
But your variable isn't even named productId. It's named id. So the code should be
session.get(Product.class, id);
This is beginner Java stuff. I strongly suggest you practice with simpler Java exercises before using Spring and Hibernate, which are complex stuff.
session.get accepts two parameters, one is the class of your entity and the other one is the identifier
Product product = (Product) session.get(Product.class,id);

Generics and the Play Framework

I am using the Play Framework in it's current version and my model classes extend play.db.jpa.JPABase.
Today I tried to make an often used type of query generic and define a static helper method to construct it.
I wrote the following:
import play.db.jpa.Model;
import play.libs.F;
public class GenericQueries {
public static <T extends Model> F.Option<T> firstOption(
Class<T> clazz,
String query,
Object... parameters){
final T queryResult = T.find(query,parameters).first();
return (queryResult == null) ?
F.Option.<T>None() :
F.Option.Some(queryResult);
}
}
However, I get the following error:
Execution exception
UnsupportedOperationException occured : Please annotate your JPA model with #javax.persistence.Entity annotation.
I debugged into the method, at runtime T seems to be correctly set to it's corresponding Model class. I even see the annotation.
I suspect some class enhancing voodoo by the play guys responsible for this, but I am not entirely sure.
Any ideas?
Update: added Model class as Requested
Here is a shortened Version of one of the Model classes I use.
package models;
import org.apache.commons.lang.builder.ToStringBuilder;
import play.data.validation.Required;
import play.db.jpa.Model;
import play.modules.search.Field;
import play.modules.search.Indexed;
import javax.persistence.Column;
import javax.persistence.Entity;
import java.util.Date;
#Entity #Indexed
public class FooUser extends Model {
#Required
public Date firstLogin;
#Field
#Required(message = "needs a username")
#Column(unique = false,updatable = true)
public String name;
#Field
public String description;
#Required
public boolean isAdmin;
#Override
public String toString(){
return new ToStringBuilder(this)
.append("name", name)
.append("admin", isAdmin)
.toString();
}
}
In Play entites should extend play.db.jpa.Model and use #Entity annotation (class level).
For what you say I understand that you are extending play.db.jpa.JPABase.
This may be the reason of the issue, as Play (as you point) dynamically enhances classes and it may be clashing with your inheritance.
EDIT: I tested the issue
The problem is that Play is not enhancing the object T. This means that the find method called id the one of GenericModel (parent of Model) whose implementation is to throw an exception with the message.
The enhancer seems to detect only the classes with #Entity.
Even the solution of mericano1 doesn't work, the enhancer doesn't pick it. So I feel you won't be able to use that method in Play.
The best way to do that is to use a base class that extends play.db.jpa.Model with just the static methods that will be shared by the subclasses.
Add the #Entity annotation to the base class and no class fields.
import play.db.jpa.Model;
import play.libs.F;
public class BaseModel extends Model {
public static <T extends Model> F.Option<T> firstOption(
Class<T> clazz,
String query,
Object... parameters){
final T queryResult = T.find(query,parameters).first();
return (queryResult == null) ?
F.Option.<T>None() :
F.Option.Some(queryResult);
}
}
And then
#Entity
public class FooUser extends BaseModel {
....
}

Categories

Resources