Here is a DAO i have created for a rooms library with a list of participants. The data is very simple.
package com.example.tag;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
#Dao
public interface ParticipantDAO {
#Query("SELECT * FROM Participants ORDER BY Name")
LiveData<List<Participant>> getAllParticipants();
#Query("SELECT * FROM Participants LIMIT 1")
Participant[] getAnyParticipant;
#Insert
void insert(Participant participant);
#Update
void update(Participant participant);
#Delete
void delete(Participant participant);
#Query("DELETE FROM Participants")
void deleteAll();
}
The problem is with the second #Query statement (getAnyParticipant). I receive the error: "'#Query' not applicable to field".
I am attempting to modify the android tutorials for my needs (using participants instead of words) located here: https://codelabs.developers.google.com/codelabs/android-training-room-delete-data/index.html?index=..%2F..android-training#2
What am I doing wrong?
Only method can be annotated with #Query. Here, you are trying to annotate a class field with #Query. You missed a pair of parentheses.
Related
Using Micronaut data v3, I created the following simple classes:
MyEntity.java
package test;
import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;
#MappedEntity
public class MyEntity {
#id
#GeneratedValue(GeneratedValue.Type.AUTO)
Long id;
String name;
}
MyRepo.java:
package test;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;
#JdbcRepository(dialect = Dialect.MYSQL)
public interface MyRepo extends CrudRepository<MyEntity, Long> {
}
The project can build without above 2 classes. Once I add these 2 classes, I got the error
java: Unable to implement Repository method: MyRepo.updateAll(Iterable arg0). No possible implementations found.
I am new to web app development. I am trying to expose the category ID:s so that I can implement "search by category" in my app.
But even after writing the below code I am not able to expose the ID:s.
I have seen some solutions, but they were of very little use to me because of the incompetence.
I am using Eclipse IDE.
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.EntityType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.http.HttpMethod;
import com.kausar.ecommerce.entity.Product;
import com.kausar.ecommerce.entity.ProductCategory;
#Configuration
public class MyDataRestConfig implements RepositoryRestConfigurer {
private EntityManager entityManager;
#Autowired
public MyDataRestConfig(EntityManager theEntityManager) {
entityManager = theEntityManager;
}
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
HttpMethod[] theUnsupportedActions = {HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE};
// disable HTTP methods for Product: PUT, POST and DELETE
config.getExposureConfiguration()
.forDomainType(Product.class)
.withItemExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions))
.withCollectionExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions));
// disable HTTP methods for ProductCategory: PUT, POST and DELETE
config.getExposureConfiguration()
.forDomainType(ProductCategory.class)
.withItemExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions))
.withCollectionExposure((metdata, httpMethods) -> httpMethods.disable(theUnsupportedActions));
// call an internal helper method
exposeIds(config);
}
private void exposeIds(RepositoryRestConfiguration config) {
// expose entity ids
//get a list of all entity classes from the entity manager
Set<EntityType<?>> entities = entityManager.getMetamodel().getEntities();
//create an array of the entity types
List<Class> entityClasses = new ArrayList<>();
//get the entity types for the entities
for (EntityType tempEntityType : entities) {
entityClasses.add(tempEntityType.getJavaType());
}
//expose entity ids for the array of entity/domain types
Class[] domainTypes = entityClasses.toArray(new Class[0]);
config.exposeIdsFor(domainTypes);
}
}
just call the helper method and remove the other code :
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
exposeIds(config);
}
you need to override this method of RepositoryRestConfigurer interface :
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
//all code
}
it is perfectly working for me.....
CorsRegistry cors => add this as a second parameter in configureRepositoryRestConfiguration method
Tried to get the returned value of the method in thymeleaf template but faced an issue. following is the environment
Controller class :
#Component
#Controller
public class HighController {
#GetMapping("/abcdata")
public String customerForm(Model model) throws IOException, InterruptedException {
model.addAttribute("abcdata", new CostDataModel());
return "abcdata";
}
}
getter and setter
import java.util.List;
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Setter
#Getter
#NoArgsConstructor
#Component
public class CostDataModel {
public SubList abcdata;
}
Main Class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
#ComponentScan
#SpringBootApplication
public class AbcmanagementApplication {
public static void main(String[] args) {
SpringApplication.run(CostmanagementApplication.class, args);
}
}
thymeleaf template view (abcdata.html)
<div class="starter-template">
<form action="#" th:action="#{/abcdata}" th:object="${abcdata}" method="post">
<div class="form-group">
<label for="subs">Choose subs</label>
<select class="form-control selectpicker" th:field="*{abcdata}" id="abcdata">
<option value="">Nothing selected</option>
<option th:each="abcdata : ${abcdata}"
th:value="${abcdata.abcdata}"
th:text="${abcdata}">abcdata
</option>
</select>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
</div>
SubList class
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
#Component
public class SubList {
#Autowired
private RequestToken rt;
public List<String> getSub() throws IOException, InterruptedException
{
// some code here
return list;
}
}
I need to access the entire list returned by the getSub() method in the thymeleaf template. but instead of list, it is returning the entire object. In thymeleaf, I am using drop down field to populate entire list but some issue.
Start by removing #Component from the objects that you put in the Model (so CostDataModel and SubList). This annotation means that you want the Spring container to create a single instance, but this is not want you want here.
Remove #Component from HighController. You already have #Controller which is enough to have Spring pick up the class as a singleton with component-scanning.
What is the use of RequestToken inside SubList? As SubList is not a Spring singleton anymore, the autowiring will not work. If you really need it, maybe pass it manually via the constructor.
With th:object="${abcdata}", you select the CostDataModel instance in Thymeleaf. When you do th:field="*{abcdata}" in the <select>, it means that Thymeleaf will call the getAbcData() method on the selected CostDataModel, which returns the SubList instance. This is not what you want, you should use simple String field. It is a bit hard to guess what the exact solution is to your question, maybe you can use some better names than abcdata everywhere to better understand your question. In any case, you might want read about Using HTML select options with Thymeleaf on my blog to understand more about this and then maybe update your question if things are still not working.
This is how I resolved it. Instead of creating the new instance of CostDataModel () and passing as model attribute , copied the entire method code of getSub() in the controller class. see below
#Controller
public class HighController {
#GetMapping("/abcdata")
public String customerForm(Model model) throws IOException, InterruptedException {
// all the code of getSub() method
model.addAttribute("abcdata", abcdata);
return "abcdata";
}
}
when I try to use Generic Dao in android Room I get this Erro :
Cannot use unbound generics in query methods. It must be bound to a type through base Dao class.
import android.arch.lifecycle.LiveData;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.RawQuery;
import android.arch.persistence.room.Update;
import java.util.List;
#Dao
public interface BaseDaoAccess<T> {
#Insert
Long Insert(T entity);
#Update
void Update(T entity);
#Delete
void Delete(T entity);
#RawQuery
LiveData<List<T>> RowQuery(String query);
}
Due to type erasure, Java can't tell at runtime what T you mean. You can provide this information by creating a subtype that has the T bound to a specific type, such as this:
public interface CarDao extends BaseDaoAccess<Car> { }
I found strange behaviour in my Play 1.2.x application
For example we has following code:
app/models/Account.java:
package models;
import javax.persistence.Entity;
import play.db.jpa.Model;
#Entity
public class Account extends Model {
public String username;
}
app/coutrollers/Application.java:
package controllers;
import play.mvc.Controller;
import java.util.List;
import models.Account;
public class Application extends Controller {
public static void index() {
Account account = Account.find("username LIKE ?", "username1").first();
account.username = "username3";
List<Account> accounts = Account.all().fetch();
render(account, accounts);
}
}
app/views/Application/index.html:
#{extends 'main.html' /}
#{set title:'Home' /}
<h2>Working!</h2>
${account.username}
<ul>
#{list items:accounts, as:'acc'}
<li>${acc.username}</li>
#{/list}
</ul>
With following accounts in database:
username1
username2
Output will be following:
Working!
username3
username3
username2
But must be as:
Working!
username3
username1
username2
What is this???
Play bug?
Java static context feature?
JPA feature?
...?
RESOLVED
Thanks for #millimoose. All that needs is a detach():
package controllers;
import play.mvc.Controller;
import java.util.List;
import models.Account;
import play.db.jpa.JPA;
public class Application extends Controller {
public static void index() {
Account account = Account.find("username LIKE ?", "username1").first();
account.username = "username3";
JPA.em().detach(account);
List<Account> accounts = Account.all().fetch();
render(account, accounts);
}
}
JPA works just like every other ORM on earth, in that when you look up the same database record twice, you will get the same object. The .first() query caches the Account internally (to track changes done to it done within a unit of work), and the .all().fetch() call just gives you that cached object again.
I'm not familiar with the Play! ORM stuff, but "raw" JPA has EntityManager.detach() to make it stop tracking a given entity instance. (And thus give you a new copy whenever the corresponding DB record is retrieved again.)