Mapping objects from Room Persistence - android-room

I have classes - Subject.java
#Entity(tableName = Constants.SUBJECT_ENTITY)
public class Subject {
#PrimaryKey
private int id;
#ColumnInfo(name = "name")
private String name;
...
}
Grade.java
#Entity(tableName = Constants.GRADE_ENTITY,
foreignKeys = #ForeignKey(
entity = Subject.class,
onDelete = CASCADE,
parentColumns = "id",
childColumns = "subjectId"))
public class Grade implements Serializable {
#PrimaryKey
private int id;
#ColumnInfo(name = "semester")
private int semester;
#ColumnInfo(name = "subjectId")
private int subjectId;
...
}
SubjectAndAllGrades.java
public class SubjectAndAllGrades {
public int id;
public String name;
#Relation(parentColumn = "id", entityColumn = "subjectId")
public List<Grade> oceny;
...
}
I have performed some query in my SubjectDAO
#Query("SELECT distinct s.id as id, s.name as name " +
"FROM subject s, grade g " +
"WHERE s.id = g.subjectId " +
"AND g.semester = :semester ")
Flowable<List<SubjectAndAllGrades>> getSubjectAndAllItsGradesForSemester(int semester);
In this query as you can probably guess Im trying to select all Subjects with its grades with specific semester. However results of this query return list of SubjectAndAllGrades objects connected by subjectId key, but with no respect to the condition
g.semester = :semester
How could I achive this query?

Related

MapStruct doesn't convert right from List<Integer> ids to List<Product>

I have an Order entity which looks like this
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private int id;
#Enumerated(EnumType.STRING)
#Column(name = "order_status")
private OrderStatus status;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH})
#JoinTable(name = "order_product"
,joinColumns = #JoinColumn(name = "order_id")
,inverseJoinColumns = #JoinColumn(name = "product_id"))
private List<Product> productList;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#Column(name = "ordered_at")
private LocalDateTime orderTime;
#OneToOne
#JoinTable(name = "order_payment"
,joinColumns = #JoinColumn(name = "order_id",referencedColumnName = "id")
,inverseJoinColumns = #JoinColumn(name = "payment_id", referencedColumnName = "id"))
private Payment payment;
#ManyToOne
#JoinColumn(name = "shop_id")
private Shop shop;
...
contsructor getter and setters
}
OrderPostDto
public class OrderPostDto {
private int id;
private OrderStatus status;
private int userId;
private LocalDateTime orderTime;
private List<Integer> productIds;
private int shopId;
...
constructor getter and setters
}
MapStruct OrderMapper
#Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {ProductService.class, ShopService.class, UserService.class})
public interface OrderMapper {
OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);
OrderDto orderToDto(Order order);
#Mapping(source = "userId", target = "user")
#Mapping(source = "productIds", target = "productList")
#Mapping(source = "shopId", target = "shop")
Order dtoToOrder(OrderPostDto dto);
}
As you can see the OrderDto accepts Product ids as Integers and OrderMapper should Map them to the object from database table of products. But it generates code like this:
protected List<Product> integerListToProductList(List<Integer> list) {
if ( list == null ) {
return null;
}
List<Product> list1 = productService.getAllProducts();
for ( Integer integer : list ) {
list1.add( productService.getProductById( integer.intValue() ) );
}
return list1;
}
But for some reason it creates list1 which contains all the items from database List<Product> list1 = productService.getAllProducts();
But I need to achieve this behaviour List<Product> list1 = new ArrayList<>(list.size()); How do I make it generate this way?
I've solved my issue, I just defined mapper as an abstract class with implementation of this particular method. So it will look like this:
#Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {ProductService.class, ShopService.class, UserService.class})
public abstract class OrderMapper {
#Autowired
protected ProductService productService;
public abstract OrderDto orderToDto(Order order);
#Mapping(source = "userId", target = "user")
#Mapping(source = "productIds", target = "productList")
#Mapping(source = "shopId", target = "shop")
public abstract Order dtoToOrder(OrderPostDto dto);
public List<Product> integerListToProductList(List<Integer> list) {
if ( list == null ) {
return null;
}
List<Product> list1 = new ArrayList<>(list.size());
for ( Integer integer : list ) {
list1.add( productService.getProductById( integer.intValue() ) );
}
return list1;
}
}

#SqlResultSetMapping unknown columns referenced in entity mapping

I am trying to map only certain fields to the entity object using a native SQL query :
#NamedNativeQuery(name = "CustomerEntity.findOnlyNameAndPhoneFromCustomer", query = "select customer_name, customer_email from customer",
resultSetMapping = "nativeMapping")
#SqlResultSetMappings(value = {
#SqlResultSetMapping(name = "nativeMapping",
entities = {
#EntityResult(
entityClass = CustomerEntity.class,
fields = {
#FieldResult(name = "name", column = "customer_name"),
#FieldResult(name = "email", column = "customer_email")
}
)})})
#Entity
class CustomerEntity {
//getter and setter fields
#Column(name="customer_name")
private String name;
#Column(name="customer_email")
private String email;
#Column(name="address")
private String adddress;
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Access(AccessType.PROPERTY)
#Column(columnDefinition = "VARCHAR(36)", name = "customer_guid")
#Type(type = "uuid-char")
private UUID guid;
#Embedded
private AuditFields audit;
}
Repository:
#Query(nativeQuery = true)
List<CustomerEntity> findOnlyNameAndPhoneFromCustomer();
I am not trying to map all the fields that are present in the customer table to CustomerEntity, I am only projecting certain fields.
This is giving me errors like:
17:44:37.841 [ERROR] o.h.e.j.s.SqlExceptionHelper - The column name address2_6_0_ is not valid.
There is no column called address2_6_0_ in my table, but there is a column called address, why is the address column being renamed and referenced here ?
I am only referencing customer_name and customer_email.
What is going on ?
Thanks.
entities is for "mapping to entities".
#EntityResult:
If this annotation is used, the SQL statement should select all of the columns that are mapped to the entity object.
Therefore, you should use classes and #ConstructorResult for "mapping to DTOs".
#NamedNativeQuery(name = "CustomerEntity.findOnlyNameAndPhoneFromCustomer",
query = "select customer_name, customer_email from customer",
resultSetMapping = "nativeMapping")
#SqlResultSetMappings(value = {
#SqlResultSetMapping(name = "nativeMapping",
classes = #ConstructorResult(columns = { #ColumnResult(name = "customer_name"), #ColumnResult(name = "customer_email") },
targetClass = CustomerEntity.class)) })
#Entity
public class CustomerEntity {
public CustomerEntity() {
}
public CustomerEntity(String name, String email) {
this.name = name;
this.email = email;
}
...
}

Spring boot JPA - Insert or update a list of entities

I have a repo with a unique constraint on 2 fields, connection_id and token_type:
#Entity
#Table(
name = "business_api_token",
schema = "public",
uniqueConstraints = {
#UniqueConstraint(
name = "business_api_token_unique_connection_id_and_token_type",
columnNames = {"connection_id", "token_type"}
)
}
)
public class BusinessApiToken {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
#JoinColumn(
name = "connection_id",
nullable = false,
foreignKey = #ForeignKey(
name = "fk_business_api_token_connection_id"
)
)
private AccountingConnection connection;
#Column(name = "token_type")
#Enumerated(EnumType.STRING)
private ApiTokenType tokenType;
#Column(name = "token_value")
private String tokenValue;
...
}
I saw some posts saying add a custom query, something like this:
#Modifying
#Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);
But how would I do this for a list? I was doing this:
businessApiTokenRepository.saveAll(tokens)
Which gives an error.
The tokens are created elsewhere without knowledge of existing ones, I can do another query to check first but that seems inefficient, and I have to do this all over.
Thanks

Andorid room two primaryKeys , one autoGenerate

I want to have two primary keys, one should be autogenerated, I try do this:
#Entity(tableName = "object_to_group", primaryKeys = {"id" , "object_id"},)
public class ObjectsToGroup {
#ColumnInfo(name = "id",autoGenerate = true)
public long id;
but compilators show me error
when I do this:
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
public long id;
a compilator show me error, what I should to do?
It is not possible with a composite primary key to add auto-increment. As an alternative, you can use unique indices. for example
#Entity(tableName = "object_to_group", indices = {#Index(value =
{"object_id"}, unique = true)})
public class ObjectsToGroup {
#PrimaryKey(autoGenerate = true)
private int id;
#ColumnInfo(name = "object_id")
private int object_id;
}

Error using sql statement in Android Room:SQL error or missing database (no such column:xx)

I used the following statement in mysql to query the data successfully:
"SELECT * FROM (SELECT * FROM `im_msg_hist` ORDER BY dTime DESC) AS T where toId='xxxx' or frmId='xxxx' GROUP BY toId".
but when i using such a statement in Android Room gives an error:"There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: tb_msg.id)"
this is Entity :
#Entity(tableName = "tb_msg")
public class Message {
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
private long id;
#ColumnInfo(name = "send_id")
private String sendId;
#ColumnInfo(name = "receive_id")
private String receiveId;
...
}
this is dao:
#Dao
public interface MessageDao {
#Query("SELECT * FROM (SELECT * FROM tb_msg ORDER BY time DESC) AS T WHERE send_id=:userId or receive_id=:userId GROUP BY send_id")
LiveData<List<PersonalMsg>> getGroupByReceiveId(String userId);
}
You should clarify table name columns name for room. I suggest you to refer this doc
Entity(tableName = "tb_msg")
public class Message {
#PrimaryKey
#ColumnInfo(name = "id")
private long id;
#ColumnInfo(name = "send_id")
private String sendId;
#ColumnInfo(name = "receive_id")
private String receiveId;
...
}

Resources