i have base entity like
#MappedSuperclass
public class BaseEntityCore implements Serializable {
#CreatedBy
#Column(name = "olusturan", /* nullable = false, */ length = 50, updatable = false)
private String createdBy;
#CreatedDate
//#NotNull
#Column(name = "olusturma_tarihi", nullable = false, updatable = false)
private LocalDateTime createdDate ;
#LastModifiedBy
#Column(name = "guncelleyen", length = 50)
private String lastModifiedBy;
#LastModifiedDate
#Column(name = "guncelleme_tarihi")
private LocalDateTime lastModifiedDate;
#Column(name = "aktif")
private int aktif;
// getter and setter
and a entity extends this base entity like
#Entity
#Table(name = "foo")
#EntityListeners(value = { AbstractEntityListenerCore.class })
public class foo extends BaseEntityCore {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="foo_name")
private String fooName;
//getter and setter
}
with spring , spring jpa. i also have entity repo like
public interface FooRepository extends JpaRepository<Foo, Long> {
Optional<Foo> findByFooName(String name);
}
now i can save entity with foo.setAktif(1). after saving foo i see on table aktif is 1. After that i run findByFooName method. this turns the object but this object has 2 aktif properties. first is aktif and value is 1 and the other is BaseEntityCore.aktif and value is 0. i check with if clause like
if(foo.getAktif()==1){
//do something
}
else {
//throws exception;
}
i cant get it why always throws exception.
You don't need your if else clause.
Just search always for Entities with "Aktif" == 1.
So extend your repo class with an other method
Optional<Foo> findByFooNameAndAktif(String name, int aktif);
and only search for the "aktif" you want.
But your question is about the 2 properties of "Aktif" right?
Related
I am still working on my very first solo spring boot project. It is suppose to be a Rest API using the MariaDB example database Nation. There is the country_languages table which receives two foreign keys that also are the primary keys and has another regular field. First foreign key is the id from countries table and the second one is the id from languages table. When I use the save() method in order to create a new tuple I get this error:
org.springframework.dao.InvalidDataAccessApiUsageException: Provided id of the wrong type for class me.givo.nationdbapiproject.model.CountryLanguages. Expected: class me.givo.nationdbapiproject.model.CountryLanguagesId, got class java.lang.Integer; nested exception is java.lang.IllegalArgumentException: Provided id of the wrong type for class me.givo.nationdbapiproject.model.CountryLanguages. Expected: class me.givo.nationdbapiproject.model.CountryLanguagesId, got class java.lang.Integer
This is the country_languages table from the MariaDB example:
create table country_languages(
country_id int,
language_id int,
official boolean not null,
primary key (country_id, language_id),
foreign key(country_id)
references countries(country_id),
foreign key(language_id)
references languages(language_id)
);
I am using an #Embeddable class CountryLanguagesId in order to make a composite key as I found in this reference.
#Embeddable
public class CountryLanguagesId implements Serializable {
#Column(name = "country_id")
private Integer countryId;
#Column(name = "language_id")
private Integer languageId;
public CountryLanguagesId() {
}
public CountryLanguagesId(Integer countryId, Integer languageId) {
this.countryId = countryId;
this.languageId = languageId;
}
// + getters and setters
After that I created the entity for the country_languages table and its repository:
#Entity
#Table(name = "country_languages")
public class CountryLanguages {
#EmbeddedId
CountryLanguagesId countryLanguagesId = new CountryLanguagesId();
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#MapsId("countryId")
#JoinColumn(name = "country_id")
private Countries countries;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#MapsId("languageId")
#JoinColumn(name = "language_id")
private Languages languages;
#Column(name = "official", length = 1, nullable = false)
private Integer official;
public CountryLanguages() {
}
public CountryLanguages(Countries country, Languages language, Integer official) {
this.countries = country;
this.languages = language;
this.official = official;
}
// + getters and setters
#Repository
public interface ICountryLanguagesJpaRepository extends JpaRepository<CountryLanguages, Integer> {
}
There are the countries and languages entities:
#Entity
#Table(name = "countries")
public class Countries {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "country_id", length = 11, nullable = false)
private Integer countryId;
#Column(name = "name", length = 50, nullable = true)
private String name;
#Column(name = "area", nullable = false)
private BigDecimal area;
#Column(name = "national_day", nullable = true)
private java.sql.Date nationalDay;
#Column(name = "country_code2", length = 2, nullable = false)
private String countryCode2;
#Column(name = "country_code3", length = 3, nullable = false)
private String countryCode3;
#OneToMany(mappedBy = "countries", cascade = CascadeType.ALL)
private Set<CountryLanguages> countryLanguages;
public Countries() {
}
public Countries(String name, BigDecimal area, Date nationalDay, String countryCode2, String countryCode3) {
this.name = name;
this.area = area;
this.nationalDay = nationalDay;
this.countryCode2 = countryCode2;
this.countryCode3 = countryCode3;
}
#Entity
#Table(name = "languages")
public class Languages {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "language_id", length = 11, nullable = false)
private Integer languageId;
#Column(name = "language", length = 50, nullable = false)
private String language;
#OneToMany(mappedBy = "languages", cascade = CascadeType.ALL)
private Set<CountryLanguages> countryLanguages;
public Languages() {
}
public Languages(String language) {
this.language = language;
}
public Integer getLanguageId() {
return languageId;
}
These are the entries I do when get the error:
#DataJpaTest
#AutoConfigureTestDatabase(replace = Replace.NONE)
public class ICountryLanguagesJpaRepositoryTest {
#Autowired
private ICountriesJpaRepository countries;
#Autowired
private ILanguagesJpaRepository languages;
#Autowired
private ICountryLanguagesJpaRepository repository;
#Test
public void shouldSaveAndRemoveContinents() {
Countries patu = new Countries("Patu", new BigDecimal(67822.34), new Date(12321233232L), "PU", "PTU");
countries.save(patu);
Languages patuano = new Languages("Patuano");
languages.save(patuano);
CountryLanguages pLanguages = new CountryLanguages(patu, patuano, 0);
repository.save(pLanguages);
assertEquals(1, repository.findAll().size());
System.out.println(repository.findAll());
repository.deleteById(1);
assertEquals(0, repository.findAll().size());
}
I am doing this using a H2 database. Here is the complete debug console output. Sorry but cant paste it here due characters limitation.
Thanks!
Your repository definition is wrong. You should specify the embeddable type as primary key type:
#Repository
public interface ICountryLanguagesJpaRepository extends JpaRepository<CountryLanguages, CountryLanguagesId> {
}
I have the following entity with the Constrainsts:
// Associated entry
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = {"userId", "associationDate"}))
public class Association extends coreEntity {
#Column(nullable = false)
private Long userId;
#Column(nullable = false)
private LocalDate associationDate;
#Column(nullable = false)
private LocalTime start;
#Column(nullable = false)
private LocalTime end;
private Duration breakTime;
#Column(nullable = false)
#OneToMany(fetch = FetchType.EAGER)
private Set<ProjectEntry> projects;
// getter setter
}
// the entry that causes the Problems with unique constraints
#Data
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = {"projectId", "userId", "date"}))
public class ProjectEntry extends CoreEntity {
#Column(nullable = false)
private Long projectId;
#Column(nullable = false)
private Long userId;
#Column(nullable = false)
private Duration duration;
#Column(nullable = false)
private LocalDate anyDate;
//getter setter
}
Service Impl method
#Override
#Transactional
public Association create(Association association ) {
checkNotNull(association);
association.setId(null);
association.getProjects().forEach(projectEntry -> {
checkObjectNotNull(projectEntry );
projectEntryRepo.save(projectEntry);
});
// Here is the problem
}
return associationRepo.save(association);
Here an exception will be thrown, when the constraint is violated.
But if the first object of the List is valid and the second violates the Unique constraint, the first Entry-create will be still commited. But none should be commited, if one is wrong. All Requests should rollback.
How should I annotated the method or deal with this issue ?
#Transactional(rollbackFor = {Exception_NAME.class,...})
public Association create(Association association ) {...}
Add #Valid to validate Set<ProjectEntry>
Try to update your code as below
#OneToMany(cascade = [CascadeType.ALL]) it will save the ProjectEntity
Association class
// Associated entry
#Entity
#Table(uniqueConstraints = #UniqueConstraint(columnNames = {"userId", "associationDate"}))
public class Association extends coreEntity {
#Column(nullable = false)
private Long userId;
#Column(nullable = false)
private LocalDate associationDate;
#Column(nullable = false)
private LocalTime start;
#Column(nullable = false)
private LocalTime end;
private Duration breakTime;
#Column(nullable = false)
#Valid
#OneToMany(cascade = [CascadeType.ALL])
private Set<ProjectEntry> projects;
// getter setter
}
Service Impl
#Override
#Transactional
public Association create(Association association ) {
checkNotNull(association);
association.setId(null);
return associationRepo.save(association);
}
Set autocommit to false at start of function and after processing all objects successfully then commit the changes
I currently have an Entity as below:
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long productId;
private String productImage;
private String productTitle;
private String productDescription;
private Integer productPrice;
private Date createdAt;
private Date updatedAt;
Upon creation of this object, the value of createdAt and updatedAt shows null in the database and was wondering how I can implement code so that createdAt and updateAt automatically gets inserted?
My post method is as below:
#PostMapping("/products")
public ProductResponse createProduct(#Validated #RequestBody ProductForm productForm) {
Product product = productForm.asProduct();
Product createdProduct = productRepository.save(product);
return new ProductResponse(createdProduct, "Product created");
}
JPA
There isn't anything as convenient as annotating the Timestamp field directly but you could use the #PrePersist, #PreUpdate annotations and with little effort achieve the same results.
Hibernate
#CreationTimestamp - Documentation
#UpdateTimestamp - Documentation
Spring Data JPA
#CreatedDate - Documentation
#LastModifiedDate - Documentation
Extend the following abstract class in your entity:
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
public abstract class DateAudit implements Serializable {
#CreatedDate
#Column(name = "created_at", nullable = false, updatable = false)
private Date createdAt;
#LastModifiedDate
#Column(name = "updated_at")
private LocalDateTime updatedAt;
}
Don't forget to enable JPA Auditing feature using #EnableJpaAuditing
Read this: https://docs.spring.io/spring-data/jpa/docs/1.7.0.DATAJPA-580-SNAPSHOT/reference/html/auditing.html
With the mix of #dimitrisli and #buddha answers, something pretty clean is
#Data
#MappedSuperclass
public abstract class BaseEntity {
#Column(updatable = false)
#CreationTimestamp
private LocalDateTime createdAt;
#UpdateTimestamp
private LocalDateTime updatedAt;
}
And now you all your entity can extend that class like so
#Data
#Entity
#EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {
#Id
#GeneratedValue
public UUID id;
public String userName;
public String email;
public String firstName;
public String lastName;
}
Note that you might not need #Data & #EqualsAndHashCode annotations from lombok as it generate getter/setter
You can create a BaseEntity. Each entity extends the BaseEntity. In the Base entity ,it will set the time automatically
#Data
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity implements Serializable {
#Id
#Column(name = "Id")
private String id;
#Column(name = "deleted", columnDefinition = "Bit(1) default false")
private boolean deleted = false;
#Column(name = "DataChange_CreatedBy", nullable = false)
private String dataChangeCreatedBy;
#Column(name = "DataChange_CreatedTime", nullable = false)
private Date dataChangeCreatedTime;
#Column(name = "DataChange_LastModifiedBy")
private String dataChangeLastModifiedBy;
#Column(name = "DataChange_LastTime")
private Date dataChangeLastModifiedTime;
#PrePersist
protected void prePersist() {
if (this.dataChangeCreatedTime == null) dataChangeCreatedTime = new Date();
if (this.dataChangeLastModifiedTime == null) dataChangeLastModifiedTime = new Date();
}
#PreUpdate
protected void preUpdate() {
this.dataChangeLastModifiedTime = new Date();
}
#PreRemove
protected void preRemove() {
this.dataChangeLastModifiedTime = new Date();
}
}
I am not so into Spring Data JPA and I have the following problem trying to implement a named query (the query defined by the method name).
I have these 3 entity classes:
#Entity
#Table(name = "room_tipology")
public class RoomTipology implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "tipology_name")
private String name;
#Column(name = "tipology_description")
private String description;
#Column(name = "time_stamp")
private Date timeStamp;
#OneToMany(mappedBy = "roomTipology")
private List<Room> rooms;
#OneToOne(mappedBy = "roomTipology")
private RoomRate roomRate;
// GETTER AND SETTER METHODS
}
That represents a tipology of room and that contains this field
#OneToMany(mappedBy = "roomTipology")
private List<Room> rooms;
So it contains the list of room associated to a specific room tipology, so I have this Room entity class:
#Entity
#Table(name = "room")
public class Room implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "id_accomodation_fk", nullable = false)
private Accomodation accomodation;
#ManyToOne
#JoinColumn(name = "id_room_tipology_fk", nullable = false)
private RoomTipology roomTipology;
#Column(name = "room_number")
private String number;
#Column(name = "room_name")
private String name;
#Column(name = "room_description")
#Type(type="text")
private String description;
#Column(name = "max_people")
private Integer maxPeople;
#Column(name = "is_enabled")
private Boolean isEnabled;
// GETTER AND SETTER METHODS
}
Representing a room of an accomodation, it contains this annoted field:
#ManyToOne
#JoinColumn(name = "id_accomodation_fk", nullable = false)
private Accomodation accomodation;
And finally the Accomodation entity class:
#Entity
#Table(name = "accomodation")
public class Accomodation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy = "accomodation")
private List<Room> rooms;
#Column(name = "accomodation_name")
private String name;
#Column(name = "description")
#Type(type="text")
private String description;
// GETTER AND SETTER METHODS
}
Ok, so now I have this Spring Data JPA repository class for RoomTipology:
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public interface RoomTipologyDAO extends JpaRepository<RoomTipology, Long> {
}
Here I want to define a named query method that return to me the list of all the RoomTipology object related to a specific accomodation, I have done it using SQL and it works fine:
SELECT *
FROM room_tipology as rt
JOIN room r
ON rt.id = r.id_room_tipology_fk
JOIN accomodation a
ON r.id_accomodation_fk = a.id
WHERE a.id = 7
But now I want to translate it in a named query method (or at least using HQL)
How can I do it?
Please Try:
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public interface RoomTipologyDAO extends JpaRepository<RoomTipology, Long> {
List<RoomTipology> findByRooms_Accomodation(Accomodation accomodation);
}
The query builder mechanism built into Spring Data repository infrastructure is useful for building constraining queries over entities of the repository. The mechanism strips the prefixes find…By, read…By, query…By, count…By, and get…By from the method and starts parsing the rest of it
At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties.
Doc:Here
Is there a way, using Hibernate or JPA annotations, to override the optionality of a field in a subclass? Take the following example:
Parent Class
This is a base class that defines a number of common fields. For the example below, I am just showing a single field that I want to override in a few sub classes. In the #MappedSuperclass, this field is required (doesn't allow null).
#MappedSuperclass
public abstract class GenericLog {
protected String sessionId;
#Basic(optional = false)
#Column(name = FIELD__SESSION_ID__COLUMN, length = 50)
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}
Child Class
This is a subclass. It has the same sessionId field defined in the parent class, the only difference is that the field should allow nulls in this class.
#Entity
#Table(name = LogError.TABLE_NAME)
#Cache(usage = CacheConcurrencyStrategy.NONE)
public class LogError extends GenericLog {
#Basic(optional = true)
#Column(name = FIELD__SESSION_ID__COLUMN, length = 50)
#Override
public String getSessionId() {
return super.getSessionId();
}
#Override
public void setSessionId(String sessionId) {
super.setSessionId(sessionId);
}
}
I tried using the #AttributeOverride annotation, but that didn't work, even specifying the nullable property.
P.S. I'm using Hibernate 4.1.9 (JPA 2.0 annotations).
I think there's some non-documented interaction between #Basic and #Column that prevent the effect of #AttributeOverride.
Remove the #Basic and move the annotation to the field level instead of method level did the trick for me:
Here is my setup:
#MappedSuperclass
public abstract class GenericLog {
#Column(name = "sessionId", length = 50, nullable = false)
protected String sessionId;
// getter setter here
}
#Entity
#Table(name = "child")
#AttributeOverride(column = #Column(name = "sessionId", length = 50, nullable = true), name = "sessionId")
public class ChildEntity extends SuperClass {
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// getter setter here
}
#Entity
#Table(name = "child2")
public class ChildEntity2 extends SuperClass {
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// Getter setter here
}
Here's the result: