I have two models, Purchase and Tag.
A Purchase can have many Tags (One to Many relationship).
What is the best (Efficent/Cleanest/etc) way to return all purchases that have one or more tags? (The actual tag entities dont have to be returned).
I'm currently using a column in the purchase table to determine if it has been tagged but would like to remove it (See PurchaseDAO for it been used)
PurchaseController:
#RequestMapping(value = "purchases/tagged", method = RequestMethod.GET)
#ResponseBody
public final List<Purchase> getTagged()
{
return RestPreconditions.checkNotNull(purchaseService.getTagged());
}
#RequestMapping(value = "purchases/pending", method = RequestMethod.GET)
#ResponseBody
public final List<Purchase> getPending()
{
return RestPreconditions.checkNotNull(purchaseService.getPending());
}
PurchaseService:
#Service
public class PurchaseService implements IPurchaseService
{
#Autowired
private IPurchaseDAO purchaseDAO;
public PurchaseService()
{
}
#Transactional
public List<Purchase> getAll()
{
return purchaseDAO.findAll();
}
#Transactional
public List<Purchase> getPending()
{
return purchaseDAO.getPending();
}
#Transactional
public List<Purchase> getTagged()
{
return purchaseDAO.getTagged();
}
}
PurchaseDAO:
#Repository
public class PurchaseDAO extends AbstractJpaDAO<Purchase> implements IPurchaseDAO {
#PersistenceContext
EntityManager entityManager;
public PurchaseDAO() {
setClazz(Purchase.class);
}
public List<Purchase> getPending() {
return entityManager.createQuery("from Purchase where tagged = 0")
.getResultList();
}
public List<Purchase> getTagged() {
return entityManager.createQuery("from Purchase where tagged = 1")
.getResultList();
}
}
Both my Purchase and Tag DAOs extend the following AbstractJpaDAO:
public abstract class AbstractJpaDAO<T extends Serializable> implements
IAbstractJpaDAO<T> {
private Class<T> clazz;
#PersistenceContext
EntityManager entityManager;
public void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T findOne(final Long id) {
return entityManager.find(clazz, id);
}
public List<T> findAll() {
return entityManager.createQuery("from " + clazz.getName())
.getResultList();
}
public void save(final T entity) {
entityManager.persist(entity);
}
}
Thanks
JB Suggestion Update
After changing PurchaseDAO getTagged() to:
public List<Purchase> getTagged() {
return entityManager.createQuery("SELECT p FROM Puchase p INNER JOIN p.tags")
.getResultList();
}
I get following error:
TRACE [http-bio-8080-exec-3] o.s.w.c.s.AnnotationConfigWebApplicationContext [AbstractApplicationContext.java:322] Publishing event in Root WebApplicationContext: ServletRequestHandledEvent: url=[/PurchaseAPIServer/api/purchases/tagged]; client=[192.168.1.17]; method=[GET]; servlet=[PurchaseAPIServer]; session=[null]; user=[null]; time=[411ms]; status=[failed: org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.ast.QuerySyntaxException: Puchase is not mapped [SELECT p FROM Puchase p JOIN p.tags tag]; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.ast.QuerySyntaxException: Puchase is not mapped [SELECT p FROM Puchase p JOIN p.tags tag]]
select p from Purchase p inner join p.tags
The inner join just makes there is at least one tag for the purchase.
Related
I have a simple document:
#Document
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString
public class ProductUnit {
#Id
String id;
private String name;
private Integer price;
private LocalDateTime localDateTime;
}
Simple MongoRepository :
public interface productRepo extends MongoRepository<ProductUnit,String> {
ProductUnit deleteByName(String name);
List<ProductUnit> findByPrice(Integer price);
}
and Service :
#Service
public class productServiseImpl implements productServise {
#Autowired
productRepo repository;
#Override
public ProductUnit saveOrUpdate(ProductUnit productUnit) {
System.out.println("inside save or update");
return repository.save(productUnit);
}
#Override
public List<ProductUnit> findAll() {
return repository.findAll();
}
#Override
public ProductUnit deleteUnitByPrice(String name) {
return repository.deleteByName(name);
}
#Override
public List<ProductUnit> findByPrice(Integer price) {
return repository.findByPrice(price);
}
}
Now , inside RestController , I pass id through a post request and use a random class to generate a random value of the price and name .At this stage everything is fine, i.e. all values were initialized correctly, but when it comes to service.saveOrUpdate(forSave) It stores the value incorrectly, i.e. the request returns an empty json and the findAll method returns a list of empty json.Can you tell me what the error is? thanks
#RestController
public class productUnitRestController {
#Autowired
productServise service;
#Autowired
Supplier<MetaInfGenerator> generatorSupplier;
#GetMapping(path = "/all")
public List<ProductUnit> getAllProoduct(){
return service.findAll();
}
#PostMapping(path = "/products")
public ProductUnit createProoduct(#RequestParam("id") Optional<String> newId){
System.out.println("***** iside PostMapping ******");
MetaInfGenerator generator = generatorSupplier.get();
System.out.println("***** supplier PostMapping ******");
ProductUnit forSave = ProductUnit.builder()
.id(newId.get())
.name(generator.getRandomString())
.price(generator.getRandomInteger())
.localDateTime(LocalDateTime.now()).build();
System.out.println(forSave);
return service.saveOrUpdate(forSave);
}
}
I'm trying to get proficient in generics in Java. I have some 100 entities that use the same findBy method in JPA interface. Almost all of them require a call to AwrSnapDetails so instead of adding
#ManyToOne private AwrSnapDetails awrSnapDetails; to each Entity, I've created a HelperEntity class and using #Embedded annotation. Now I have gotten to the point in coding where I can't figure out what I am doing wrong and how to go about resolving this error.
Entity
#Entity
public class AwrMemStats {
String description;
double begin_;
double end_;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
#Embedded
private HelperEntity helperEntity;
public AwrMemStats() {
}
public AwrMemStats(String description, double begin_, double end_, AwrSnapDetails awrSnapDetails) {
this.description = description;
this.begin_ = begin_;
this.end_ = end_;
HelperEntity h = new HelperEntity(awrSnapDetails);
}
// getters/setters removed for clarity
}
Embedded Entity
#Embeddable
public class HelperEntity implements Serializable{
private static final long serialVersionUID = 1L;
#ManyToOne
AwrSnapDetails awrSnapDetails;
public HelperEntity() {
}
public HelperEntity(AwrSnapDetails awrSnapDetails) {
super();
this.awrSnapDetails = awrSnapDetails;
}
public AwrSnapDetails getAwrSnapDetails() {
return awrSnapDetails;
}
public AwrSnapDetails setAwrSnapDetails(AwrSnapDetails awrSnapDetails) {
return this.awrSnapDetails = awrSnapDetails;
}
}
Service Class
#Service
public class HelperService<T> {
#Autowired
private HelperRepository<T> repository;
public void add(T entity) {
repository.save(entity);
}
public void add(List<T> entities) {
repository.saveAll(entities);
}
public T get(T entity) {
T t = repository.findByHelperEntityAwrSnapDetailsStartSnapIdAndHelperEntityAwrSnapDetailsInstanceDetailDbNameAndHelperEntityAwrSnapDetailsInstanceDetailDbId(
((HelperEntity) entity).getAwrSnapDetails().getStartSnapId(),
((HelperEntity) entity).getAwrSnapDetails().getInstanceDetail().getDbName(),
((HelperEntity) entity).getAwrSnapDetails().getInstanceDetail().getDbId());
//((AwrMemStats) entity).getHelperEntity().getAwrSnapDetails().getStartSnapId(),
//((AwrMemStats) entity).getHelperEntity().getAwrSnapDetails().getInstanceDetail().getDbName(),
//((AwrMemStats) entity).getHelperEntity().getAwrSnapDetails().getInstanceDetail().getDbId());
if (t!= null) {
return t;
}
return null;
}
}
Controller
#RestController
public class HelperController<T> {
#Autowired
private HelperService<T> service;
public void add(T entity) {
service.add(entity);
}
public void add(List<T> entities) {
service.add(entities);
}
public T get(T entity) {
return service.get(entity);
}
}
Execution
getAwrSnapDetails() initilized in HelperLoader
#Component
public class LoadAwrMemStats extends HelperLoader{
#Autowired
private HelperController<AwrMemStats> controller;
public void doThis() {
AwrMemStats profile = new AwrMemStats("a",1.0,1.0,getAwrSnapDetails());
AwrMemStats s = controller.get(profile);
ANd finally the ERROR message
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
...
...
Caused by: java.lang.ClassCastException: net.mharoon.perfmon.awr.entities.AwrMemStats incompatible with net.mharoon.perfmon.awr.entities.HelperEntity
at net.mharoon.perfmon.awr.service.HelperService.get(HelperService.java:27)
at net.mharoon.perfmon.awr.controller.HelperController.get(HelperController.java:24)
...
...
Update this code works but only for given class AwrMemStats.
public List<T> get(T entity) {
List<T> ts = repository.findByHelperEntityAwrSnapDetailsStartSnapIdAndHelperEntityAwrSnapDetailsInstanceDetailDbIdAndHelperEntityAwrSnapDetailsInstanceDetailDbName(
//((HelperEntity) entity).getAwrSnapDetails().getStartSnapId(),
//((HelperEntity) entity).getAwrSnapDetails().getInstanceDetail().getDbName(),
//((HelperEntity) entity).getAwrSnapDetails().getInstanceDetail().getDbId());
((AwrMemStats) entity).getHelperEntity().getAwrSnapDetails().getStartSnapId(),
((AwrMemStats) entity).getHelperEntity().getAwrSnapDetails().getInstanceDetail().getDbId(),
((AwrMemStats) entity).getHelperEntity().getAwrSnapDetails().getInstanceDetail().getDbName());
if (!ts.isEmpty()) {
return ts;
}
return null;
}
The reason is because you are returning an Object that is not AwrMemStats and assigning it to AwrMemStats.
A simple work around is to replace
public T get(T entity)
with
public <T extends AwrMemStats> T get(T entity)
EDIT : Another solution (which is more generic) is..
replace
public class AwrMemStats
with
public class AwrMemStats extends HelperEntity
then replace
AwrMemStats s = controller.get(profile);
with
AwrMemStats s = (AwrMemStats) controller.get(profile);
I have tried to delete a row from database using Spring data deleteById method but it returns null.
ProductServiceImpl
public void removeOne(Long id) {
Product product = findById(id);
productRepository.deleteById(product);
ProductRepository
public interface ProductRepository extends CrudRepository<Product, Long> {
void deleteById(Product product);
Controller
#RequestMapping(value="/remove", method=RequestMethod.POST)
public String remove(#ModelAttribute("id") String id, Model model) {
productService.removeOne(Long.parseLong(id.substring(10)));
List<Product> productList = productService.findAll();
model.addAttribute("productList", productList);
System.out.println("deleted successfully !!!!");
return "redirect:/product/productList";
}
Why you write it complex. Some code not necessary .First, you extends CrudRepository,it mean you don't need create custom method void deleteById(Product product); because crud contain method deleteById.
Second, Controller why you using : #RequestMapping(value="/remove", method=RequestMethod.POST) . I think it must : #DeleteMapping("/remove") . And in controller only call.
#Autowired
private ProductRepository productRepository;
#DeleteMapping("/remove/{id}")
public String remove(#PathVariable String id) {
productRepository.deleteById(id);
return "redirect:/product/productList";
}
#Autowired
private ProductRepository productRepository;
#RequestMapping(value="/remove", method=RequestMethod.POST)
public String remove(#RequestParam String id) {
productRepository.deleteById(id);
return "redirect:/product/productList";
}
Fighting with TestNG, Spring an Hibernate. I'm writing test for Service class, and it's always failure. But without test class works fine. So App is working, but tests don't want to.
Here is my test class
#Transactional
public class BorrowerServiceTest {
#Mock
BorrowerDAOImpl borrowerDAO;
#InjectMocks
BorrowerService borrowerService;
#BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void persistTest() {
Borrower borrower = new Borrower.BorrowerBuilder().firstName("Lars").lastName("Urlich").adress("LA")
.phoneNumber("900900990").build();
borrowerService.persist(borrower);
List<Borrower> borrowerList = borrowerService.getBorrowerByName("Lars Urlich");
Assert.assertEquals(true, borrower.equals(borrowerList.get(0)));
}
}
My BorrowerService:
#Service("borrowerService")
#Transactional
public class BorrowerService {
#Autowired
private BorrowerDAO borrowerDAO;
public List<Borrower> getBorrowers() {
return borrowerDAO.getBorrowers();
}
public List<Borrower> getBorrowerByName(String name) {
return borrowerDAO.getBorrowerByName(name);
}
public boolean removeBorrower(Borrower borrower) {
return borrowerDAO.removeBorrower(borrower);
}
public boolean persist(Borrower borrower) {
return borrowerDAO.persist(borrower);
}
}
My BorrowerDAOImpl:
#Repository("borrowerDAO")
#Transactional
public class BorrowerDAOImpl extends DAO implements BorrowerDAO {
#Override
public List<Borrower> getBorrowers() {
List<Borrower> borrowerList = null;
Query query = entityManager.createQuery("SELECT B FROM Borrower B");
borrowerList = query.getResultList();
return borrowerList;
}
#Override
public List<Borrower> getBorrowerByName(String name) {
List<Borrower> borrowerList = null;
String[] values = name.split(" ");
Query query = entityManager.createQuery("SELECT B FROM Borrower B WHERE B.firstName LIKE '" + values[0]
+ "' AND B.lastName LIKE '" + values[1] + "'");
borrowerList = query.getResultList();
return borrowerList;
}
#Override
public boolean removeBorrower(Borrower borrower) {
String firstName = borrower.getFirstName();
String lastName = borrower.getLastName();
Query query = entityManager
.createQuery("DELETE Borrower where FIRST_NAME LIKE :FirstName AND LAST_NAME LIKE :LastName");
query.setParameter("FirstName", firstName);
query.setParameter("LastName", lastName);
query.executeUpdate();
return true;
}
#Override
public boolean persist(Borrower borrower) {
entityManager.persist(borrower);
return true;
}
}
and abstract DAO:
#Repository
#Transactional
public abstract class DAO {
#PersistenceContext
protected EntityManager entityManager;
}
Maven returns failure:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.get(LinkedList.java:476)
at com.me.service.test.BorrowerServiceTest.persistTest(BorrowerServiceTest.java:41)
I also had to fight with this. The problem here is that your test runs in it's own transaction, so nothing will be committed during method's execution. Now here is what I did:
public class IntegrationTest extends SomeTestBase
{
#Autowired
private PlatformTransactionManager platformTransactionManager;
private TransactionTemplate transactionTemplate;
#Autowired
private BeanToTest beanToTest;
#Override
#Before
public void setup()
{
super.setup();
this.transactionTemplate = new TransactionTemplate(this.platformTransactionManager);
}
#Test
public void fooTest()
{
// given
// when
boolean result = this.transactionTemplate.execute(new TransactionCallback<Boolean>()
{
#Override
public Boolean doInTransaction(TransactionStatus status)
{
return IntegrationTest.this.beanToTest.foo();
}
});
// then
}
}
This allows you to have methods execute within a separate transaction. Please note that you might declare some variables as final.
Hope that helps.
Check the Spring documentation: it looks your test class should extend AbstractTestNGSpringContextTests.
Use #Commit annotation on the whole test class or even method to persist changes made in the test. For more information https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#commit
I use Spring & Hibernate and i would like to get a product with his id in my DAO.
#Repository
#Transactional
public class ProductDaoImpl implements ProductDao {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private SessionFactory sessionFactory;
public List<Product> getProductList() {
return sessionFactory.getCurrentSession().createQuery("from Product p order by p.productName asc").list();
}
public Product getProductById(int productId) {
String hql = "from Product p where p.productId = :id";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setInteger("id", productId);
return null;
}
}
For example when i would like to get all my products i return list of them (calling function getProductList() ), but now i want to call getProductById but i don't know how i could return something with the "Product" type.
Thanks.
In your getProductById(int productId) method:
return (Product) query.uniqueResult();