Why is my JPA derived query case insensitive by default? - jpa

All materials I have read so far indicate that case sensitive is the default behavior for a JPA query, and you need to add IgnoreCase to add that feature to the query. However, when I run my findByName(String name) derived query, it is able to identify the "checking" and "savings" accounts without case. Do I have something setup that would cause this? How can I switch to case sensitive?
#Entity
#Table(name = "gl_account")
public class Account extends Entry {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "number", unique = true, nullable = false)
#NotBlank
private String number;
#Column(name = "name", unique = true, nullable = false)
#NotBlank
private String name;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(
name = "element_id",
referencedColumnName = "id",
foreignKey = #ForeignKey(name = "fk__gl_account__element_id"),
nullable = false
)
#NotNull
private Element element;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(
name = "player_id",
referencedColumnName = "id",
foreignKey = #ForeignKey(name = "fk__gl_account__player_id")
)
private Player player;
// constructors, setters, getters, equals, hashcode
}
#Repository
public interface AccountRepository extends PagingAndSortingRepository<Account,Integer> {
Optional<Account> findByName(String name);
}
#Service
public class AccountService {
private final AccountRepository REPO;
#Autowired
public AccountService(AccountRepository repo) {
REPO = repo;
}
public Account findByName(String name) {
return REPO.findByName(name).orElse(null);
}
}
#DisplayName("can find one by name")
#ParameterizedTest
#ValueSource(strings = {
"cHeCkInG",
"sAvInGs",
"Accounts Payable"
})
public void findByName_test1(String name) {
Account account = svc.findByName(name);
assertNotNull(account);
}
INSERT INTO gl_account
(number, name, element_id, player_id)
VALUES
('1000', 'Checking', 1, 1),
('1001', 'Savings', 1, 2),
('2000', 'Accounts Payable', 2, NULL),
('3000', 'Retained Earnings', 3, NULL),
('4000', 'Salary', 4, NULL),
('4001', 'Interest Income', 4, NULL),
('5000', 'Food', 5, NULL),
('5001', 'Entertainment', 5, NULL),
('6000', 'Unrealized Gain/Loss', 6, NULL),
('99', 'NINETY-NINE', 6, NULL);

There are databases that compare case insensitive by default.
https://www.oreilly.com/library/view/mysql-cookbook/0596001452/ch04s10.html#:~:text=In%20summary%2C%20comparisons%20are%20case,%2C%20SET%20%2C%20or%20TEXT%20columns.

Related

EntityListener saving null value in subclass

I have a Customer entity class and a CorporateCustomer entity class, CorporateCustomer extends Customer and Customer extends AuditEntity and AuditEntity extends BaseEntity. Both AuditEntity and BaseEntity have EntityListener and implemented prePersist value.
CorporateCustomer Entity
#Data
#Entity
#Table(name = "t_cust_corp")
#Where(clause = "sts_cd not in ('D', 'I')")
#TypeDef(typeClass = JsonBinaryType.class, name = "jsonb")
public class CorporateCustomer extends Customer {
#Column(name = "cust_id")
private UUID custId;
#Type(type = "jsonb")
#Column(columnDefinition = "jsonb", name = "obligor_dtl")
private Serializable obligorDetail;
}
Customer Entity
#Data
#Entity
#Table(name = "t_customer")
#Where(clause = "sts_cd not in ('D','I')")
#Inheritance(strategy = InheritanceType.JOINED)
public class Customer extends BaseEntity {
#Column(name = "cif_no")
private String cifNo;
#Column(name = "cust_name")
private String customerName;
#Column(name = "mt_cust_typ_cd")
private String customerTypeCd;
#Column(name = "mt_cust_id_typ_cd")
private String customerIdTypeCd;
#Column(name = "cust_id_no")
private String customerIdNo;
}
BaseEntity (Library Generated)
#Generated
protected BaseEntity(final BaseEntity.BaseEntityBuilder<?, ?> b) {
this.id = b.id;
this.statusCode = b.statusCode;
this.version = b.version;
this.createdBy = b.createdBy;
this.createdTime = b.createdTime;
this.lastUpdatedBy = b.lastUpdatedBy;
this.lastUpdatedTime = b.lastUpdatedTime;
}
BaseEntityListener (part of codes)
#PrePersist
public void prePersist(BaseEntity baseEntity) {
log.trace("prePersist baseEntity:" + baseEntity);
baseEntity.setCreatedBy(requestSynchronizationManager.getUserIdForAudit());
baseEntity.setCreatedTime(OffsetDateTime.now());
baseEntity.setVersion(0);
if (baseEntity.getStatusCode() == null) {
baseEntity.setStatusCode(StatusCode.INACTIVE);
}
}
AuditEntity
#Data
#SuperBuilder
#MappedSuperclass
#NoArgsConstructor
#AllArgsConstructor
#EntityListeners({AuditEntityListener.class})
public abstract class AuditEntity extends BaseEntity {
private static final long serialVersionUID = 1778847390000617814L;
#Column(name = "crt_by_usr_nm", updatable = false)
private String createdByUsername;
#Column(name = "upd_by_usr_nm", insertable = false)
private String updatedByUsername;
}
AuditEntityListener (part of codes)
#Slf4j
#Component
public class AuditEntityListener {
#PrePersist
public void prePersist(AuditEntity auditEntity) {
log.trace("prePersist auditEntity:" + auditEntity);
auditEntity.setCreatedByUsername(requestSynchronizationManager.getLegalName());
}
}
During save Customer only, it works as charm, but if save CorporateCustomer, I got the error my BaseEntity property is null (hit null-constraint). Sts_cd should be automatically setValue during #prePersist. Below is the error,
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "sts_cd" violates not-null constraint
Detail: Failing row contains (0f0a348f-8ae2-493e-905e-20a82e87a4ae, 6eeadc61-ba2d-4ca3-9e09-2730d061ff82, {"rmNameCd": "01", "gamUnitCd": "EB", "lamUnitCd": "EB", "rmName..., [{"custCompany": "ABC Company", "extRatingKMV": 10, "lastApprove..., {"primarySectorCd": "C", "primaryIndustryCd": "46221", "primaryR..., null, null, null, null, null, null, null, 0).
I debugged the code, the BaseEntityListener actually get triggered when creating new record using JPA saveAndFlush, but turn out hit this error. Anyone has idea on this?

Exclude some fields of REST Data with Panache

Just having a look at REST Data with Panache wondering if it is possible to exclude some entity fields from beeing exposed by the rest resource, as we need the generated REST resources only for read access pattern.
However, in the docs https://quarkus.io/guides/rest-data-panache I did not find a way to do it.
Looks like it is using Jackson for JSON, so #JsonIgnore should work for you.
#JSonIgnore can be used at the field level, or you can add it on the Getter or Setter if you want only specific parts to be ignored.
#Entity
#Table(name = "order_item")
public class OrderItem extends PanacheEntityBase {
#Id
#GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
#GeneratedValue(generator = "uuid")
#Column(name = "id", length = 36, nullable = false)
#Getter
#Setter
private String id;
#Getter
#Setter
#ManyToOne(targetEntity = Order.class)
#JsonIgnore
#JoinColumn(name = "order_id")
private Order orderId;
#Getter
#Setter
#JsonIgnore
#ManyToOne(targetEntity = Item.class)
#JoinColumn(name = "item_id")
private Item itemId;
#Getter
#Setter
#Column(name = "quantity", nullable = false)
private Integer quantity;
#Getter
#Setter
#Column(name = "price_total", nullable = false)
private Double priceTotal;
#Getter
#Setter
#Column(name = "note", columnDefinition = "text")
private String note;
}
Or you can use #JsonIgnoreProperties at the top level of the class:
#Entity
#JsonIgnoreProperties(value = { "creator", "created" }, allowSetters = false, allowGetters = true)
public class UpdateUserDeviceTokenRequest extends PanacheEntity {
#NotNull
#NotEmpty
#NotBlank
public String userDeviceToken;
#ManyToOne()
#JoinColumn(name = "creatorUser", insertable = true, updatable = false)
public AppUser creator;
#Column(insertable = true, updatable = false)
public LocalDateTime created;
public UpdateUserDeviceTokenRequest() {
}
#PrePersist
void onCreate() {
this.created = LocalDateTime.now();
}
public UpdateUserDeviceTokenRequest(#NotNull #NotEmpty #NotBlank String userDeviceToken) {
super();
this.userDeviceToken = userDeviceToken;
}
}
Please see https://github.com/quarkusio/quarkus/issues/10339 for possible issue that might arise

Hibernate error: mappedBy reference an unknown target entity property

I am having an issue in setting up a many to many relationship in my entities. And I don't understand why
failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: cardgame.bean.User.card in cardgame.bean.Card.users
My Entities:
#MappedSuperclass
#Data
public class BaseEntity implements Serializable {
#Id
#Column(name = "id", nullable = false, unique = true)
private String id;
public BaseEntity() {
this.id = UUID.randomUUID().toString();
}
}
My user emtity:
#Data
#Entity
#Table(name = "users")
public class User extends BaseEntity {
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "uuid", nullable = false)
private String uuid;
#Column(name = "email", nullable = false, unique = true)
private String email;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Card> cards;
#Column(name = "isActive", nullable = false)
private boolean isActive;
}
My card entity:
#Data
#Entity
#Table(name = "cards")
public class Card extends BaseEntity {
#OneToMany(mappedBy = "card")
private List<User> users;
#Column(name = "strength", nullable = false)
private int strength;
#Column(name = "isActive", nullable = false)
private boolean isActive;
}
The users and cards tables have a many-to-many relationship via user_card table:
#Data
#Entity
#Table(name = "user_card")
public class UserCard implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Id
#ManyToOne
#JoinColumn(name = "card_id", nullable = false)
private Card card;
#Column(name = "cardCount", nullable = false)
private int cardCount;
}
What am i doing incorrect. Please help me

Error in a ManyToMany Relationship on Hibernate-JPA

I have a large DB on MySql Workbench and I'm trying to map the relationship between the entities on Eclipse Mars thanks to Hibernate and the JPA module. The fact is that I receive the error:
"In attribute 'personAddresses', the "mapped by" attribute 'peopleAdd' has an invalid mapping type for this relationship."
This are the entities involved.
1
I've to say that making a forward engineering, Hibernate creating for me an AddressId class, where the composite primary key of Address is mapped. I suspect that the problem could be this, but I'm not certain, can you help me please?
Under I post the code so that it's more clear to understand how the classes are implemented.
#Entity
#IdClass(AddressId.class)
#Table(schema = "YouDroop", name = "Address")
public class Address implements Serializable
{
...
private Collection<Person> peopleAdd = new HashSet<Person>();
#Id
#Column(name = "Address", length = 45, unique = true, nullable = false)
private String address;
#Id
#Column(name = "Number", unique = true, nullable = false)
private int number;
...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "PersonHasAddress",
joinColumns = {
#JoinColumn(name = "Address_Address", referencedColumnName = "Address", nullable = false),
#JoinColumn(name = "Address_Number", referencedColumnName = "Number", nullable = false)
},
inverseJoinColumns = {#JoinColumn(name = "Person_Email", referencedColumnName = "Email", nullable = false)}
)
public Collection<Person> getPeopleAddressed(){
return this.peopleAdd;
}
public void setPeopleAddressed(Collection<Person> people){
this.peopleAdd = people;
}
}
public class AddressId implements Serializable
{
private String address;
private int number;
public AddressId(){}
public AddressId(String address, int number) {
super();
this.address = address;
this.number = number;
}
...
}
#Entity
#Table(name = "Person", schema = "YouDroop", uniqueConstraints =
{ #UniqueConstraint(columnNames = "NickName"),
#UniqueConstraint(columnNames = "Password") })
public class Person implements Serializable
{
...
private Collection<Address> addresses = new HashSet<Address>();
...
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "peopleAdd")
public Collection<Address> getPersonAddresses(){
return this.addresses;
}
public void setPersonAddresses(Collection<Address> addresses){
this.addresses = addresses;
}
}
Since you placed you #ManyToMany annotation on your getter method (or property) and not on the field. The mappedBy attribute should reference the property instead and not the field.
#ManyToMany
public Collection<Person> getPeopleAddressed() {
...
}
So your mappedBy attribute should have been
#ManyToMany(mappedBy="peopleAddressed")
public Collection<Address> getPersonAddresses() {
...
}

Seeing "referencedColumnNames(ID) ... not mapped to a single property" error with a 1-M relationship after adding a composite key to the "1" side

I have an existing JPA entity ("Reference") with an ID column as its primary key that it inherits from a base class "BaseEntity" (using the #MappedSuperclass annotation on the superclass).
I also have a 1-M relationship between a Reference and another entity called Violation. Violation was previously defined with a foreign key "REFERENCE_ID" to the "ID" column of the Reference entity.
Recently, I tried to add an unrelated composite key to the Reference entity. This should not have affected the 1-M relationship between Reference and Violation. However, when I run the code in my tomcat server, I see the following stack trace:
Caused by: org.hibernate.AnnotationException: referencedColumnNames(ID) of org.qcri.copydetection.sdk.metastore.entity.Violation.reference referencing org.qcri.copydetection.sdk.metastore.entity.Reference not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:205) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:110) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.processEndOfQueue(AnnotationConfiguration.java:541) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.processFkSecondPassInOrder(AnnotationConfiguration.java:523) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:380) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1206) ~[hibernate-core-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1459) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1086) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:685) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
... 39 common frames omitted
Here is the code for the 3 classes involved:
#Entity
#Table(name = "REFERENCE")
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
#IdClass(Reference.ContextualName.class)
public class Reference extends BaseEntity {
#Column(name= "LOCATION", unique=true)
#XmlElement
private String location;
#Id
#AttributeOverrides({
#AttributeOverride(name = "name", column = #Column(name = "NAME")),
#AttributeOverride(name = "account", column = #Column(name = "ACCOUNT_ID"))
})
#Column(name = "NAME")
#XmlElement
private String name;
#ManyToOne(optional=false)
#XmlTransient
#JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Reference() {}
public Reference(String name) {
setName(name);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public Account getAccount() {
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
#Embeddable
private class ContextualName implements Serializable {
private static final long serialVersionUID = -3687389984589209378L;
#Basic(optional = false)
#Column(name = "NAME")
#XmlElement
private String name;
#ManyToOne(optional=false)
#XmlTransient
#JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
ContextualName() {}
}
}
#MappedSuperclass
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
#XmlElement
private Long id;
#Basic(optional = true)
#Column(name = "CREATED", insertable = false, updatable = false, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
#Temporal(TemporalType.TIMESTAMP)
#XmlElement
private Date creationDate;
protected BaseEntity() {}
public Long getId() {
return id;
}
public void setId(Long id) {
if(this.id==null) {
this.id = id;
} else if (this.id!=id) {
throw new IllegalArgumentException("Cannot change the id after it has been set, as it is a generated field.");
}
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
if(this.creationDate==null) {
this.creationDate = creationDate;
} else if (this.creationDate!=creationDate) {
throw new IllegalArgumentException("Cannot change the creation-date after it has been set, as it is a generated field.");
}
}
}
#Entity
#Table(name = "VIOLATION")
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Violation extends BaseEntity {
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#JoinColumn(name = "REFERENCE_ID", referencedColumnName = "ID")
private Reference reference;
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#JoinColumn(name = "SUSPECT_ID", referencedColumnName = "ID")
private Suspect suspect;
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#XmlTransient
#JoinColumn(name = "SEARCH_ID", referencedColumnName = "ID")
private Search search;
#Basic(optional = false)
#Column(name = "SCORE")
#XmlElement
private double score;
public Violation() {}
public Violation(Search search, Reference ref, Suspect sus, double score) {
this.search = search;
this.reference = ref;
this.suspect = sus;
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public Reference getReference() {
return reference;
}
public void setReference(Reference reference) {
this.reference = reference;
}
public Suspect getSuspect() {
return suspect;
}
public void setSuspect(Suspect suspect) {
this.suspect = suspect;
}
public Search getSearch() {
return search;
}
public void setSearch(Search search) {
if(this.search!=null && this.search!=search) {
this.search.removeViolation(this);
}
this.search = search;
if(search!=null) {
if(!search.getViolations().contains(this)) {
search.addViolation(this);
}
}
}
}
To cut a long story short, I'm totally confused how to go about adding a composite key to an existing (legacy) entity that already has an ID column. I can't remove the ID column, nor can I change the 1-M relationship between Reference and Violation. I can't for the life of me understand the error message because the "REFERENCE_ID" foreign key column of the Violation entity is being mapped to a single "ID" column of the Reference entity.
Many thanks in advance!