Im trying to do a simple search for two columns for a table.
My customer entity class snipet:
#Entity
#Table(name = "CUSTOMER")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CUSTOMER_ID", nullable = false)
private int customer_id;
#Column(name = "FIRST_NAME", nullable = false)
private String first_name;
#Column(name = "LAST_NAME", nullable = false)
private String last_name;
#Column(name = "PHONE_NUMBER", nullable = false)
private String phone_number;
#Column(name = "EMAIL")
private String email;
my customerRepository class snipet:
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
List<Customer> findAllByFirst_nameAndLast_name(String firstName, String lastname);
}
When compiling and running springBoot i get this error:
nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.owl.owlserver.repositories.CustomerRepository.findAllByFirst_nameAndLast_name(java.lang.String,java.lang.String)! No property first found for type Customer!
So its not able to detect the fields in the customer object, should I be importing the customer class into the repository somehow?
The problem lies in your snake_case naming convention, it's recommended to use camelCase naming convention.
As the Spring docs say:
Because we treat the underscore character as a reserved character, we
strongly advise following standard Java naming conventions (that is,
not using underscores in property names but using camel case instead).
You can see a related JIRA issue here -- underscores are not supported in property names.
I would recommend keeping the properties in a camel-case as per standards
Because we treat the underscore character as a reserved character, we strongly advise following standard Java naming conventions (that is, not using underscores in property names but using camel case instead).
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CUSTOMER_ID", nullable = false)
private int customerId;
#Column(name = "FIRST_NAME", nullable = false)
private String firstName;
#Column(name = "LAST_NAME", nullable = false)
private String lastName;
#Column(name = "PHONE_NUMBER", nullable = false)
private String phoneNumber;
#Column(name = "EMAIL")
private String email;
And then query as well as per Property Expressions
List<Customer> findAllByFirstNameAndLastName(String firstName, String lastname);
The whole point of Spring JPA is to simplify query building using the methods defined in Repository. The convention is to use the camelCase for naming field in Entity and the same while writing query methods. Just change the naming of entity fields from snake case to camel case and you're good to go.
Related
I have this piece of code where the author creates a JPA Entity. Somehow, it's successfully working and that seems weird to me since not every field is annotated with "#Column". Based on that, here's my question:
How it is possible for this class to work properly (all data is being successfully recorded in the database) without every field not having a "Column" annotation (excepting "id")?
/**
* #author Ram Alapure
* #since 05-04-2017
*/
#Entity
#Table(name="User")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private long id;
private String firstName;
private String lastName;
private LocalDate dob;
private String gender;
private String role;
private String email;
private String password;
#Override
public String toString() {
return "User [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", dob=" + dob + ", email="
+ email + "]";
}
}
For instance, here's another class which is working properly as well. But this time, with a "#Column" annotation in every field. I thought it was a pre-requisite to JPA create a column from the field.
#Entity
#Table(name = "address")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "address_id")
private long id;
#Column(name = "rua")
private String street;
#Column(name = "number")
private int number;
#Column(name = "complement")
private String complement;
#Column(name = "suburb")
private String suburb;
#Column(name = "city")
private String city;
#Column(name = "state")
private String state;
#Column(name = "country")
private String country;
#Column(name = "cep")
Getters and Setters were hidden from all pieces of code since they just look like regular getters and setters, not being necessary to be shown.
If you don't specify #Column annotation (Optional) then Hibernate uses default naming stretegy by using camel case.
firstName field becomes first_name column in Database.
You can also define your own naming stretegy according to your needs.
From the documentation.
strategy ; Hibernate 5 defines a Physical and Implicit naming strategies. Spring Boot configures SpringPhysicalNamingStrategy by default. This implementation provides the same table structure as Hibernate 4: all dots are replaced by underscores and camel cases are replaced by underscores as well.
this annotation means create table in database #Entity with all field in class same the name
the spring boot scan this annotation #Entity after scan
is inject and create Bean in IOC with fields
but if used #Column this help for mapping with Table field if change colume name in dataBase
and spring boot when scan component and see this annotation the bean is change with Colume name to name in database becouse we need success mapping with data base
I have the following relationship in the data base
Database Diagram
And these are the entities
Apartment.java
#Entity
#Table(name = "apartment")
#Data
public class Apartment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_apartment")
private long id;
#ManyToMany
#JoinTable(
name = "apartment_facility",
joinColumns = #JoinColumn(name = "id_apartment"),
inverseJoinColumns = #JoinColumn(name = "id_facility"))
#Column(name = "city")
private String city;
#Column(name = "country")
private String country;
}
Facility.java
public class Facility {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_facility")
private long id;
#Column(name = "name")
private String name;
}
My question is how can I create a findBy method in JpaRepository in order to find all Apartments having the required facilities
I'm thinking of the result of this request:
api/apartments/findByFacilities?facilities=gym,pool,parking
I have tried to do a query but couldn't quite get it. Also tried using Jpa as following
List<Apartment> findByFacilities(#RequestParam("facilities") List<String> facilities);
But I'm getting the following error. Is there a walkaround?
Failed to convert from type [java.lang.String] to type [java.lang.Long]
In your first code block List <Facility> facilities = new ArrayList<>(); I guess you forgot to add the code line.
When I look at your link below, I understand that you want to search by the name of the facility.
api/apartments/findByFacilities?facilities=gym,pool,parking
For this, your code in Repository should be as follows:
List<Apartment> findDistinctByFacilitiesNameIn(List<String> facilities);
If we don't add distinct supported keyword here, each record repeats as many as the facilities it contains.
If you want to search differently like, not like, etc., See the supported keywords inside method names table here: Query Creation document.
We are using spring-boot.
I want to add conditional based constraint in java class.
For e.g.
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "user_id")
private Integer userId;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
}
Now in above code I want to put #NotNull constraint on lastName property if and only if the firstName property is not empty.
So I'am trying Spring webFlux and have following code:
#Override
public Flux<? extends AnimalDatabaseEntity> queryAnimals() {
return async(animalsRepository.findAll().stream());
}
private <T> Flux<T> async(Stream<T> stream) {
return Flux.fromStream(stream).publishOn(scheduler);
}
The problem that I get infinite recursion, because "AnimalDatabaseEntity" has field animalFeatures.
#Entity(name = "animals")
public class AnimalDatabaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Enumerated(EnumType.STRING)
#Column(name = "animal_type")
private AnimalType animalType;
#Column(name = "number_of_legs")
private Integer numberOfLegs;
#Column(name = "is_pet")
private boolean isPet;
#OneToMany(mappedBy = "animalDatabaseEntity", fetch = FetchType.EAGER)
private List<AnimalFeatureEntity> animalFeatures;
}
I don't really get why this does not work???
My best guess is AnimalFeatureEntity contains varaible of type AnimalDatabaseEntity which references back to List<AnimalFeatureEntity> while serializing thus causing an infinite recursion. You can prevent it by adding #JsonIgnore to AnimalDatabaseEntity if it suits your use case. However, if you wish to preserve the bidirectional relationship, then #JsonManagedReference/#JsonBackReference or #JsonIdentityInfo is the way to go.
For example usage, refer this article
I have several similar tables in DB.
Now I use for each table own Model and Repository
But I think, this is not right decision.
Can I make a one Model and Repository for all similar tables?
#Entity
#Table(name = "BEDROOM", schema = "public")
public class BedroomModel extends AllFinishProductModel{
#Column(name = "PHOTO")
private String photo;
#Id
#Column(name = "ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "STRUCTURE") //organza, curtain ....
private String structure;
#Column(name = "PAINT") //abstraction, geometric ....
private String paint;
#Column(name = "HEIGHT")
private String height;
#Column(name = "COLOR")
private String color;
#Column(name = "QUANTITY")
private Double quantity;
#Column(name = "PRICE")
private BigDecimal price;
#Column(name = "SEWED")
private String itIsSewed;
... getters and setters
}
I have a similar tables: CABINET, GUESTROOM, CHILDREN_ROOM, KITCHEN, CURTAIN and TULLE.
Which code should be used for repository?
I tried to find answers to the questions inhttps://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
But I don't find answers here.
Can you give advice, how to make it or link?
You can use entity inheritance with #MappedSuperclass annotation on parent class to get common properties in child classes/tables.
So, for example you have a parent Room entity with common properties, which you annotate with #MappedSuperclass.
#MappedSuperclass
public class Room {
#Column
private String name;
#Column(name = "DESCRIPTION")
private String description;
// some more common properties
}
And concrete rooms, e.g.:
#Entity
public class Bedroom extends Room
{
// common properties will be inherited
private Bed bed;
private NightLamp nightLamp;
}
Now, the important part is that Room is not mapped as any table. The room is a "virtual" table, which doesn't exist in the db. Only concrete entities exist as tables, like Bedroom.
Here you have the link to the official javadoc:
http://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html