I use Hibernate and I want to filter entities with the Hibernate filter options. But the filter will be ignored. The Workspace entity include a user entity. And i want all workspace entitys with only thise user with doesent have a NULL-Value in the E-Mail field in the database.
I look forward to hearing from you. Thanks
Workspace
#Entity
#Table(name = "WORKSPACEENTITY", schema = "pwdmanager")
#PrimaryKeyJoinColumn(name = "workspace_id", referencedColumnName = "id")
#Setter
#Getter
#FilterDef(name = "FILTER")
public class DBWorkspaceEntity{
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "wkse_space")
private List<DBPasswordEntity> pwde_password;
#OneToOne(fetch = FetchType.EAGER)
#Filters({
#Filter(name="FILTER", condition="{u}.usre_email is not null", aliases={#SqlFragmentAlias(alias="u", entity=DBUserEntity.class)}),
})
private DBUserEntity usre_user;
}
User
#Entity
#Table(name = "USERENTITY", schema = "pwdmanager")
#Setter
#Getter
#PrimaryKeyJoinColumn(name = "user_id", referencedColumnName = "id")
public class DBUserEntity{
#Basic
#Column(name = "USRE_EMAIL", nullable = true, length = 1024)
private String usre_email;
}
Hibernate
public class MasterDao{
private Session session;
private Transaction transaction;
private SessionFactory sessionFactory;
public void prepare() {
sessionFactory = HibernateUtil.getSessionFactory();
this.session = sessionFactory.openSession();
}
public void filter(final DBUserEntity usr) {
try {
session.enableFilter("FILTER");
Query query = session.createQuery("FROM " + DBWorkspaceEntity.class.getSimpleName());
List<DBWorkspaceEntity> result = query.list();
session.disableFilter("FILTER_USER");
} catch (final HibernateException ex) {
log.error(ex);
}
}
}
I think, usre_email in filter condition should be column name.
USRE_EMAIL
Related
I have two simple domain objects as follows:
USER:
#Entity
#Table(name="USER")
#IdClass(UserPK.class)
public class User implements Serializable {
//...
#Id
#Column(name = "FISCALCODE")
private String fiscalCode;
#Id
#Column(name = "USERNUMBER")
private String userNumber;
#OneToMany(mappedBy="user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Items> items;
// getters and setters
}
UserPK:
public class UserPK implements Serializable {
#Column(name = "FISCALCODE")
private String fiscalCode;
#Column(name = "USERNUMBER")
private String userNumber;
// getter and setter
}
ITEMS:
#Entity
#Table(name="ITEMS")
public class Items implements Serializable {
//...
#Id
#Column(name = "ID_ITEM")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_item_generator")
#SequenceGenerator( name = "id_item_generator", sequenceName = "ITEM_SEQ", allocationSize = 1)
private Integer id;
#ManyToOne
#JoinColumns({
#JoinColumn(name="FISCALCODE"),
#JoinColumn(name="USERNUMBER")
})
private User user;
// getters and setters
}
DB Table:
user { fiscalcode, usernumber, other columns... } // fiscalcode+usernumber = PK
items { id, fiscalcode, usernumber, other columns... } // fiscalcode,usernumber is a foreign key
CONTROLLER:
#RequestMapping(value="/user", method = RequestMethod.POST, produces = "application/json")
public Object postUser(#RequestBody(required = false) User user){
//connection etc..
session.save(user);
//...
return new ResponseEntity<>(HttpStatus.OK);
}
Why when I run the command session.save(user) Hibernate insert value null in the columns FISCALCODE and USERNUMBER of the ITEMS table?
I tried to set the ManyToOne and the JoinColumns on the getter, but the result is the same.
EDIT: i have added my method for POST operation
As it's stated in the documentation for #JoinColumns:
When the JoinColumns annotation is used, both the name and the referencedColumnName elements must be specified in each such JoinColumn annotation.
So, you should correct your mapping like below:
#ManyToOne
#JoinColumns({
#JoinColumn(name="FISCALCODE", referencedColumnName = "FISCALCODE"),
#JoinColumn(name="USERNUMBER", referencedColumnName = "USERNUMBER")
})
private User user;
Whenever a bidirectional association is formed, the application developer must make sure both sides are in-sync at all times.
So, you should have in your User entity the addItem() and removeItem() utility methods that synchronize both ends whenever a child element is added or removed like below.
#Entity
#Table(name="USER")
#IdClass(UserPK.class)
public class User implements Serializable {
//...
#OneToMany(mappedBy="user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Items> items;
// getters and setters
public void addItem(Items item) {
this.items.add(item);
item.setUser(this);
}
public void removeItem(Items item) {
this.items.remove(item);
item.setUser(null);
}
}
Example of saving:
User user = new User();
user.setFiscalCode("Code1");
user.setUserNumber("User1");
// ...
Items item1 = new Items();
Items item2 = new Items();
// ...
user.addItem(item1);
user.addItem(item2);
session.save(user);
I'm making an app that holds a UserProfile with Wallet that has many Transactions.
Here's the Transaction class:
#Entity
#Table(name = "transactions")
public class Transaction extends BaseEntity {
#Column(name = "amount", nullable = false)
private BigDecimal amount;
#Column(name = "executed_on", nullable = false)
private LocalDateTime executedOn;
#Column(name = "is_top_up")
private boolean isTopUp;
#Column(name = "note")
private String note;
#ManyToOne(targetEntity = UserProfile.class)
private UserProfile sender;
#ManyToOne(targetEntity = UserProfile.class)
private UserProfile receiver;
public Transaction() {
}
Here's the Wallet class
#Entity
#Table(name = "wallets")
public class Wallet extends BaseEntity {
#ManyToMany(targetEntity = Transaction.class, cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.EAGER)
#JoinTable(name = "wallets_transactions",
joinColumns = #JoinColumn(name = "wallet_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "transaction_id", referencedColumnName = "id")
)
private Set<Transaction> transactions;
public Wallet() {
this.transactions = new HashSet<>();
}
public Set<Transaction> getTransactions() {
return transactions;
}
public void setTransactions(Set<Transaction> transactions) {
this.transactions = transactions;
}
public void addTransaction(Transaction transaction) {
this.transactions.add(transaction);
}
}
What I want is, to get all transactions by sender and receiver search criteria. For example, user 'A' sent money to user 'B'. I'm using JpaRepository. The end result should be in a Page<Transaction> class.
So far, when using just findAllBySender(UserProfile sender, Pageable pageable), it does work and I get the exact right Transactions. But when I try Page<Transaction> findAllBySenderAndReceiver(UserProfile sender, UserProfile receiver, Pageable pageable); I get a Page<T> with 0 elements when my DB has test data with at least 1 record.
Solved. Turns out, I had a logical error. Thank you all, for your assistance.
I'm facing a difficulty in developing a server in Spring (+ Hibernate + JPA) for a project.
The structure of the server (the part of interest in this case) is composed of catalogs composed of products that can have some related feedbacks.
Here I share the 3 entities:
Catalog.java
#Entity
#Data
#Table(name = "catalog")
public class Catalog {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false, unique = true)
private String name;
private String description;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "catalog_user_id", nullable = false)
private User user;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinTable(name = "catalog_product",
joinColumns = {#JoinColumn(name = "catalog_id")},
inverseJoinColumns = {#JoinColumn(name = "product_id")}
)
private List<Product> products;
public Catalog() {}
}
Product.java
#Entity
#Data
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false, unique = true)
private String name;
private String description;
#Column(nullable = false, length = 1)
#MapKeyEnumerated(EnumType.ORDINAL)
private Category category;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "product_user_id", nullable = false)
private User user;
public Product() {}
}
Feedback.java
#Entity
#Data
#Table(name = "feedback")
public class Feedback {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "feedback_user_id", nullable = false)
private User user;
#Column(nullable = false, length = 1)
#MapKeyEnumerated(EnumType.ORDINAL)
private Rating rating;
private String text;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "product_id", nullable = false)
private Product product;
public Feedback() {}
}
The problem occurs when I try to delete some entities. What I want is:
when I delete a catalog also the catalog references in the "catalog_product" join table should be deleted (but the product linked with the catalog should not be deleted);
when I delete a product also the product references in the "catalog_product" join table and the feedbacks related to that product should be deleted;
when I delete a feedback nothing happens.
In the business layer I have this operations:
CatalogServiceImpl.java
#Service
public class CatalogServiceImpl implements CatalogService {
#Autowired
private CatalogDAO catalogDAO;
#Autowired
private ModelMapper mapper;
public CatalogDTO findById(Long id) {
Catalog catalog = catalogDAO.findById(id);
return mapper.map(catalog, CatalogDTO.class);
}
public CatalogDTO findByName(String name) {
Catalog catalog = catalogDAO.findByName(name);
return mapper.map(catalog, CatalogDTO.class);
}
public List<CatalogDTO> findByUserId(Long id) {
List<Catalog> catalogs = catalogDAO.findByUserId(id);
Type listCatalogsType = new TypeToken<List<CatalogDTO>>() {}.getType();
return mapper.map(catalogs, listCatalogsType);
}
public List<CatalogDTO> findAll() {
List<Catalog> catalogs = catalogDAO.findAll();
Type listCatalogsType = new TypeToken<List<CatalogDTO>>() {}.getType();
return mapper.map(catalogs, listCatalogsType);
}
public CatalogDTO createCatalog(CatalogDTO catalogDTO) {
Catalog catalog = mapper.map(catalogDTO, Catalog.class);
Catalog catalogFromDB = catalogDAO.save(catalog);
return mapper.map(catalogFromDB, CatalogDTO.class);
}
public CatalogDTO updateCatalog(CatalogDTO catalogDTO) {
Catalog catalog = mapper.map(catalogDTO, Catalog.class);
Catalog catalogFromDB;
if(catalogDAO.exists(catalog.getId())) {
catalogFromDB = catalogDAO.save(catalog);
} else {
catalogFromDB = null;
}
return mapper.map(catalogFromDB, CatalogDTO.class);
}
public void deleteCatalog(Long id) {
Catalog catalog = catalogDAO.findById(id);
if(catalog != null) {
catalogDAO.delete(catalog.getId());
}
}
}
ProductServiceImpl.java
#Service
public class ProductServiceImpl implements ProductService {
#Autowired
private ProductDAO productDAO;
#Autowired
private ModelMapper mapper;
public ProductDTO findById(Long id) {
Product product = productDAO.findById(id);
return mapper.map(product, ProductDTO.class);
}
public ProductDTO findByName(String name) {
Product product = productDAO.findByName(name);
return mapper.map(product, ProductDTO.class);
}
public ProductDTO findByCategory(Category category) {
Product product = productDAO.findByCategory(category);
return mapper.map(product, ProductDTO.class);
}
public List<ProductDTO> findByUserId(Long id) {
List<Product> products = productDAO.findByUserId(id);
Type listProductsType = new TypeToken<List<ProductDTO>>() {}.getType();
return mapper.map(products, listProductsType);
}
public List<ProductDTO> findAll() {
List<Product> products = productDAO.findAll();
Type listProductsType = new TypeToken<List<ProductDTO>>() {}.getType();
return mapper.map(products, listProductsType);
}
public ProductDTO createProduct(ProductDTO productDTO) {
Product product = mapper.map(productDTO, Product.class);
Product productFromDB = productDAO.save(product);
return mapper.map(productFromDB, ProductDTO.class);
}
public ProductDTO updateProduct(ProductDTO productDTO) {
Product product = mapper.map(productDTO, Product.class);
Product productFromDB;
if(productDAO.exists(product.getId())) {
System.out.println(product.toString());
productFromDB = productDAO.save(product);
} else {
productFromDB = null;
}
return mapper.map(productFromDB, ProductDTO.class);
}
public void deleteProduct(Long id) {
Product product = productDAO.findById(id);
if(product != null) {
productDAO.delete(product.getId());
}
}
}
Now, when I try performing the operations of deletion of catalog or product an error of constraint key fail is triggered. For example trying to delete a product which has a reference in the catalog_product join table:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`e01`.`catalog_product`, CONSTRAINT `FKdx5j7bcx77t7h0hjw6tvoxmp1` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`))
I don't understand if there's a way to set the relations between entities to make what I want in an automatic way with Spring, or if I have to remove records with reference manually before the deletion of the catalog/product.
Thanks a lot in advance to everyone!
Luca
Why I am getting this error? This is the portion of my daoImpl Im calling
#Transactional
#Repository
public class PersonDaoImpl implements PersonDao{
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Override
#Transactional(readOnly=true)
public List<Person> getAllPersons(){
List<Person> persons = (List<Person>) sessionFactory.getCurrentSession()
.createCriteria(Person.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
return persons;
}
Portion of my person model
#OneToMany(fetch = FetchType.LAZY, mappedBy = "person", cascade = CascadeType.ALL)
private Set<Contact> contacts;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "PERSON_ROLE", joinColumns = {
#JoinColumn(name = "person_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "role_id",
nullable = false, updatable = false) })
private Set<Role> roles = new HashSet<Role>(0);
In my service impl, I convert model to dto using BeanUtils
What am I doing wrong?
My feeling is that in a time when you try to convert the entity to dto using BeanUtils the entity is already detached (e.g. outside persistence context/hibernate session). In your Person class you have a Set<Contact> of contacts which is loaded lazily - that is why it fails.
If Contact does not contain many relations you might change to FetchType.EAGER or you can convert entity while Person is still attached.
In the BeanUtils, you need to initialize the objects via Hibernate as follows:
MyProfile pf = null;
try {
session.beginTransaction();
Query query = session.createQuery("from MyProfile as term where term.profileId=:pId ");
query.setString("pId", pid);
pf = (MyProfile)query.uniqueResult();
if(pf != null)
{
Hibernate.initialize(pf);
}
} catch (HibernateException he) {
throw he;
}
Using Hibenrate.initialize(pf) will initialize the objects contained inside MyProfile object.
I have four class; UserGroup, UserAccount, Role, UserGroupRoleRelation and my db is IBM DB2
#Entity
#Table(name = "USER_GROUP")
public class UserGroup implements Serializable {
#Id
#Column(name = "USER_GROUP_ID")
#GeneratedValue
private Long id;
......
..
#OneToMany(mappedBy = "userGroup", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UserGroupRoleRelation> userAccountsRole = new ArrayList<UserGroupRoleRelation>();
}
#Entity
#Table(name = "ROLE")
public class Role implements Serializable {
#Id
#Column(name = "ROLE_ID")
#GeneratedValue
private Long id;
......
#OneToMany(mappedBy = "role")
private List<UserGroupRoleRelation> userAccountInGroup = new ArrayList<UserGroupRoleRelation>();
}
#Entity
#Table(name = "USER_GROUP_ROLE_LINE", uniqueConstraints = #UniqueConstraint(columnNames = { "ROLE_ID", "USER_GROUP_ID" }))
public class UserGroupRoleRelation {
#Id
#GeneratedValue
#Column(name = "RELATION_ID")
private Long relationId;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "USER_ACCOUNT_USER_GROUP_ROLE_LINE", joinColumns = { #JoinColumn(name = "RELATION_ID") }, inverseJoinColumns = { #JoinColumn(name = "USER_ID") }, uniqueConstraints = #UniqueConstraint(columnNames = { "USER_ID", "RELATION_ID" }))
private List<UserAccount> userAccountList = new ArrayList<UserAccount>();
#ManyToOne
#JoinColumn(name = "USER_GROUP_ID")
private UserGroup userGroup;
#ManyToOne
#JoinColumn(name = "ROLE_ID")
private Role role;
}
#Entity
#Table(name = "USER_ACCOUNT")
public class UserAccount implements Serializable {
#Id
#Column(name = "USER_ID")
#GeneratedValue
private Long id;
.....
#ManyToMany(mappedBy = "userAccountList", cascade = CascadeType.ALL)
private List<UserGroupRoleRelation> rolesInGroup = new ArrayList<UserGroupRoleRelation>();
}
I wanna find usergroups of a useraccount and i prepared a method with criteria. its like;
#Override
#Transactional
public List<UserGroup> findUserGroupOf(UserAccount userAccount) {
Criteria criteria = getSession().createCriteria(UserGroup.class);
criteria.createAlias("userAccountsRole", "userAccountsRole");
criteria.add(Restrictions.eq("userAccountsRole.userAccountList", userAccount));
return criteria.list();
}
But when i try to get result of that method, DB2 gives to me DB2 SQL Error: SQLCODE=-313, SQLSTATE=07004, SQLERRMC=null, DRIVER=3.63.75
Probably its about creating alias on many to many relation. I dont know what should i do to create alias on many to many. How can I get result of that function?
Thank
#Override
#Transactional
public List<UserGroup> findUserGroupOf(UserAccount userAccount) {
Criteria criteria = getSession().createCriteria(UserGroup.class);
criteria.createAlias("userAccountsRole", "userAccountsRole");
criteria.createAlias("userAccountsRole.userAccountList", "userAccountList");
criteria.add(Restrictions.eq("userAccountList.id", userAccount.getId()));
return criteria.list();
}
It works for me. I mean criteria on "id". But I don't understand why I cant check equality on object instead of id when there is ManyToMany list
It is not of creating alias. You are passing an object to hibernate on which it can not make any criteria. You need to create bidirectional mapping for that.Or else if you your requirement is just to fetch the the list of UserAccountList of particular UserGroup class you can follow the below code.
#Override
#Transactional
public List<UserGroup> findUserGroupOf(long userGroupId) {
Criteria criteria = getSession().createCriteria(UserGroup.class);
criteria.add(Restrictions.eq("id",userGroupId));
criteria.createAlias("userAccountsRole", "uar");
criteria.setFetchMode("uar.userAccountList",FetchMode.JOIN);
return criteria.list();
}