I'm trying to map business object into entity but got stuck and have no idea how to resolve this.
The problem is when I try to map these attributes from DTO which are attributes of many-to-one relationship with another table.
Here is how my Entity looks like:
#Entity
#Table(name = "t_car")
public class Car extends AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "pkIdCar")
private Long id;
#Column(nullable = false, columnDefinition="VARCHAR(45)")
private String brand;
#Column(nullable = false)
private Integer productionYear;
#Column(nullable = false)
private Float engineCapacity;
#Column(nullable = false)
private Float power;
#Column(nullable = false)
private Integer distance;
#ManyToOne
#JoinColumn(name = "fkIdType")
private CarType carType;
#ManyToOne
#JoinColumn(name = "fkIdColor")
private Color color;
... }
And here is DTO:
public class CarDto {
private Long id;
private String brand;
private Integer productionYear;
private Float engineCapacity;
private Float power;
private Integer distance;
private CarTypes carType;
private ColorTypes color;
... }
CarTypes and ColorTypes are enums which have assigned number corresponding to their primary key in database. For example CarTypes is:
REGULAR_TWO_DOOR(1),
REGULAR_FOUR_DOOR(2),
STATION_WAGON(3),
MINIVAN(4),
SPORT(5),
LUXURY(6);
And here is the mapper i managed to write. How can I assign proper CarType (that's entity) to carEntity basing on CarType primary key?
public class CarMapper {
...
public static Car carDtoToCar(CarDto carDto, Car carEntity) {
if(carEntity == null) {
carEntity = new Car();
}
carEntity.setBrand(carDto.getBrand());
carEntity.setProductionYear(carDto.getProductionYear());
carEntity.setEngineCapacity(carDto.getEngineCapacity());
carEntity.setPower(carDto.getPower());
carEntity.setDistance(carDto.getDistance());
Long carTypeId = Long.valueOf(carDto.getCarType().getNumber());
Long carColorId = Long.valueOf(carDto.getColor().getNumber());
/* ? */
return carEntity;
}
}
CarType entity:
#Entity
#Table(name = "t_car_type")
public class CarType extends AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "pkIdType")
private Long id;
#Enumerated(EnumType.STRING)
#Column(nullable = false, columnDefinition="VARCHAR(45)")
private CarTypes type;
... }
Get the CarType entity based on the Cartype Id. For example:
CarType carType = entityManager.find(CarType.class, carTypeId);
And then set this carType in CarEntity as
carEntity.setCarType(carType);
Related
I have an Order entity and OrderProduct. I want to show order details on frontend and of course order products in it. So how to fetch product object in OrderProduct JSON. I'm missing product object in products array. I don't need order object one more time and i think it going to be a infinite recursion stuff with it. :)
My Order entity:
#Entity
#Getter
#Setter
#Table(name ="orders")
public class Order{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
private BigDecimal totalPrice;
#OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonManagedReference(value="orders")
private List<OrderProduct> products = new ArrayList<>();
private int userId;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date date = new Date();
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date deliveryDate;
#Enumerated(EnumType.STRING)
private OrderType orderType;
}
My OrderProduct entity:
#Entity
#Setter
#Getter
public class OrderProduct {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JsonBackReference(value="product")
#JoinColumn(name = "product_id")
private Product product;
#ManyToOne
#JsonBackReference(value="orders")
#JoinColumn(name = "order_id")
private Order order;
private Integer quantity;
}
Product entity:
#Entity
#Getter
#Setter
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String name;
private double price;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
#JsonManagedReference(value="ingredients")
private List<Ingredient> ingredients = new ArrayList<>();
#OneToMany(mappedBy = "product",fetch = FetchType.EAGER)
#JsonManagedReference(value="product")
private List<OrderProduct> products = new ArrayList<>();
private String fileName;
}
This can help annotate one of your entity clases with
#JsonIdentityInfo(
property = "id",
generator = ObjectIdGenerators.PropertyGenerator.class
)
Every time when JSON serialization go in circles object data will be replaced with object id or orher field of entity for your choose.
You can use #JsonViewannotation to define the fields that you need to serialize to JSON
How it works:
You need define class with interfaces. For example:
public class SomeView {
public interface id {}
public interface CoreData extends id {}
public interface FullData extends CoreData {}
}
Mark entity fields with #JsonView(<some interface.class>)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonView(SomeView.id.class)
private Long id;
#Column(nullable = false)
#JsonView(SomeView.CoreData.class)
private String username;
#Column(nullable = false)
#JsonView(SomeView.FullData.class)
private String email;
}
Annotate endpoint with #JsonView(<some interface.class>)
#GetMapping()
#JsonView(<some interface.class>)
public User getUser() {
return <get user entity somwhere>
}
In case #JsonView(SomeView.id.class) you will get this JSON:
{
id: <some id>
}
In case #JsonView(SomeView.CoreData.class):
{
id: <some id>,
username: <some username>
}
In case #JsonView(SomeView.FullData.class):
{
id: <some id>,
username: <some username>,
email: <some email>
}
#JsonView also works with embeded objects and you can annotate one field with multiply views classes - #JsonView({SomeView.FullData.class, SomeOtherView.OtherData.class})
In your case i think you should annotate all the fields you need except:
#OneToMany(mappedBy = "product",fetch = FetchType.EAGER)
#JsonManagedReference(value="product")
private List<OrderProduct> products = new ArrayList<>();
in Product
to avoid circular serialization
Or as alternative you can just use DTO classes or seralize oject to JSON manualy (https://thepracticaldeveloper.com/java-and-json-jackson-serialization-with-objectmapper/)
This can be done by my library beanknife
// This configure generate a class named ProductInfo which has the same shape with Product without property "products"
#ViewOf(value = Product.class, genName="ProductInfo", includePattern = ".*", excludes = {"products"})
class ProductInfoConfigure {}
// This configure generate a class named OrderProductRelation with the same shape of OrderProduct.
// But it has not order property and the type of its product property is change to ProductInfo generated above.
#ViewOf(value = OrderProduct.class, genName="OrderProductRelation", includePattern = ".*", excludes = {"order"})
class OrderProductRelationConfigure {
#OverrideViewProperty("product")
private ProductInfo product;
}
// This configure generate a class named OrderDetail with the same shape of Order.
// But the type of its products property is change to List<OrderProductRelation>
#ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
class OrderDetailConfigure {
#OverrideViewProperty("products")
private List<OrderProductRelation> products;
}
will generate these classes:
class ProductInfo {
private Long id;
private String name;
private double price;
private List<Ingredient> ingredients; // it is not processed because you have not provide the class Ingredient
private String fileName;
}
public class OrderProductRelation {
private Long id;
private ProductInfo product;
private Integer quantity;
}
public class OrderDetail {
public Long id;
private BigDecimal totalPrice;
private List<OrderProductRelation> products;
private int userId;
private Date date = new Date();
private Date deliveryDate;
private OrderType orderType;
}
Then
Order order = ...
OrderDetail orderDetail = OrderDetail.read(order);
// serialize the otherDetail instead of order.
List<Order> orders = ...
List<OrderDetail> orderDetails = OrderDetail.read(orders);
// serialize the orderDetails instead of orders.
Possible problems:
I doesn't use Lombok, so Lombok may need to be adapted because it change the byte code on the fly. But it is not a big problem, I will try to adapt it if someone commit the issue and provide enough use cases.
The generated class does not inherit the annotation on the original class. In next release I will provide a sulotion. At this moment, as a workaround, we can use custom method to convert the property manually. such as
#ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
class OrderDetailConfigure {
#OverrideViewProperty("products")
private List<OrderProductRelation> products;
#OverrideViewProperty("orderType")
public static String orderType(Order source) {
return source.getOrder().name();
}
}
The generated class will be changed to
public class OrderDetail {
public Long id;
private BigDecimal totalPrice;
private List<OrderProductRelation> products;
private int userId;
private Date date = new Date();
private Date deliveryDate;
private String orderType;
}
Update
Version 1.2.0 released. Add support of annotation inheritance.
#ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
#UseAnnotation({DateTimeFormat.class, Enumerated.class, JsonProperty.class})
class OrderDetailConfigure {
#OverrideViewProperty("products")
private List<OrderProductRelation> products;
}
generate
public class OrderDetail {
public Long id;
private BigDecimal totalPrice;
private List<OrderProductRelation> products;
private int userId;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date date;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date deliveryDate;
#Enumerated(EnumType.STRING)
private OrderType orderType;
}
Hi I want to create an Entity which doesn't have an ID.
#Entity
#Table(name="USER_PROD_LIC_TYPE_ALL")
public class UserProdLicTypeAll {
#EmbeddedId
private UserProdLicTypeAllPK id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="LICENSE_TYPE_ID")
private LicenseType licType;
....
}
since it doesn't have primary key i created Embeddable class as below:
#Embeddable
public class UserProdLicTypeAllPK {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="LICENSE_TYPE_ID")
private LicenseType licType;
...
}
The combination of these two fields returns a unique value.
But it doesn't work. I get
org.springframework.beans.factory.UnsatisfiedDependencyException: exception.
Do i need to have references in User and LicenseType entities for both UserProdLicTypeAll and UserProdLicTypeAllPK? I have tried that also but still it doesn't work.
This is my private hell. I'm not sure what the best way to solve it properly.
My best solution is:
#Entity
#Table(name = TableName.AREA_USER)
#IdClass(UserAreaPK.class)
public class UserArea implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = UserAreaPK.C_AREA_ID)
private Long areaId;
#Id
#Column(name = UserAreaPK.C_USER_ID)
private String userId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = UserAreaPK.C_AREA_ID, insertable = false, updatable = false)
private Area area;
And
/**
* Primary key for the relationship User-Area
*/
public class UserAreaPK implements Serializable {
protected static final String C_AREA_ID = "area_id";
protected static final String C_USER_ID = "user_id";
private static final long serialVersionUID = 1L;
#Id
#Column(name = C_AREA_ID)
private Long areaId;
#Id
#Column(name = C_USER_ID)
private String userId;
I'm having two entities Car and CarDescription where CarDescription is depending on another foreign key from the table Language.
What I' trying to accomplish is to have a HashMap in Car such that whenever I'm having a Car entity-object I am able to access all descriptions from the language id.
Entity Car.java
#Entity
#Table(name = "Car")
public class Car extends AbstractTimestampEntity implements Serializable {
private static final long serialVersionUID = -5041816842632017838L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#OneToMany(mappedBy="car")
#MapKeyColumn(name = "language_ID")
// #MapKey(name = "language") // does not work either
private Map<Long, CarDescription> carDescription = new HashMap<>(0);
}
Entity CarDescription.java
#Entity
#Table( name="car_description",
uniqueConstraints = {
#UniqueConstraint(columnNames={"language_id", "name"})
}
)
public class CarDescription extends AbstractTimestampEntity implements Serializable {
private static final long serialVersionUID = 2840651722666001938L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#NotNull
#ManyToOne
private Car car;
#NotNull
#OneToOne
private Language language;
// ..
}
Entity Language.java
#Entity
public class Language implements Serializable {
private static final long serialVersionUID = 3968717758435500381L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID")
private Long id;
// ..
}
The problem I am having is that the mapping gives me a map from each CarDescription.id to CarDescription.
How can I accomplish a correct mapping?
In CarDescription you need to add the languageId property:
#Column(name = "language_id", insertable = false, updatable = false)
private Long languageId;
#NotNull
#OneToOne
#JoinColumn(name = "language_id")
private Language language;
public void setLanguage(Language language) {
this.languageId = language.getId();
this.language = language;
}
Then you can use it in the Car entity like this:
#OneToMany(mappedBy="car")
#MapKey(name = "languageId")
private Map<Long, CarDescription> carDescription = new HashMap<>(0);
I am new to JPA and doing a small sample to learn about it.
But I got one problem below, please help me out, and please explain why:
I have class Customer.java, which is mapped to table customer in db:
#Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id_customer")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
// accountNumber field maps with accountNumber column in Account table
#Column(name = "loginId", unique = true)
private String loginId;
#Column(name = "password")
private String password;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "address")
private String address;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#OneToMany(mappedBy="customer")
private List<Account> accountList;
#OneToMany(mappedBy="customer")
private List<Card> cardList;
// getters and setters goes here
}
The above class has two lists, accountList and cardList, their generic Class (Card and Account) extends BaseInfo using Single table Inheritance.
Here is my BaseInfo.java:
#Entity
#Table(name = "account")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)
public class BaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "number")
private String number;
#Column(name = "availableNumber")
private Long availableNumber;
//getter and setter here
}
Class Card.java:
#Entity
#Table(name = "account")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue(value = "C")
public class Card extends BaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "cardType")
private String cardType;
#ManyToOne
#JoinColumn(name = "id_customer")
private Customer customer;
//getter and setter
}
And class Account.java:
#Entity
#Table(name = "account")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue(value = "A")
public class Account extends BaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "accountName")
private String accountName;
#Column(name = "accountType")
private String accountType;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "dt_created")
private Date createdDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "dt_lst_updt")
private Date lastUpdatedDate;
#ManyToOne
#JoinColumn(name = "id_customer")
private Customer customer;
//getter, setter
}
Then, I do a query that query customer from database with loginid and password, like this:
entityTransaction.begin();
TypedQuery<Customer> query = entityManager.createQuery(
"SELECT c FROM " + Customer.class.getName()
+ " c Where c.loginId= :loginId", Customer.class);
query.setParameter("loginId", loginId);
res = query.getSingleResult();
entityTransaction.commit();
The code run with no error, but the result is somethings strange to me: When I debug (or print out the result to jsp), accountList or cardList contains all Account of that customer, just like they don't care about the 'discriminator' column.
I have 2 questions:
How can I archive the goal that listCard contains only Card (discrimination = c) and listAccount contains only Account (discriminator = a) ?
Is there an alternative way to query listCard or listAccount without query the customer first (like I use) ??
Thank in advance! :D
I'm not sure if it's a JPA restriction or a Hibernate-specific restriction, but you may not use the same column to map two different associations.
You should use something like car_customer_id to map the association between customer and cards, and account_customer_id to map the association between customer and accounts.
I have the following
#Entity
#Table(name = "PROJECTS")
public class Project implements Serializable {
#Id
private Integer SlNo;
#Id
private Long projectNo;
private Date projectDate;
}
and in DAO class
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> countQ = cb.createQuery(Long.class);
Root<Project> empCount = countQ.from(Project.class);
countQ.select(cb.count(empCount));
TypedQuery<Long> countquery = entityManager.createQuery(countQ);// error in this line
I am getting exception java.lang.IllegalStateException: No supertype found in the above line. How can I resolve or workaround this issue? Looks like there is a bug, are there any solution to this?
I am using Hibernate 4.1.0.Final
I have resolved the issue by using #EmbeddedId in Entity class and #Embeddable in Primary Key class.
#Entity
#Table(name = "PROJECTS")
public class Project {
#Column(name = "SL_NO" , insertable = false, updatable = false)
private Integer SlNo;
#Column(name = "PROJECT_NO" , insertable = false, updatable = false)
private Long projectNo;
private Date projectDate;
#EmbeddedId
ProjectPK projectPK;
and Primary Key class
#Embeddable
public class ProjectPK implements Serializable {
#Column(name = "SL_NO")
private Integer SlNo;
#Column(name = "PROJECT_NO")
private Long projectNo;
//with hashCode and equals implementation
for the case Using #EmbeddedId, here is my solution. This code I have written in one class itself, in Entity class.
Class MyEntity - It is my actual Entity class for my table. "OtherFields" are those fields which are not part of primary key.
Class MyEntityPrimaryKeys - It is the class made for my composite key which makes a primary key for my "MyEntity" class. Here ROLLNO and AGE together makes a primary key.
MyEntity.java
#Entity
#Table(name = "myTable")
public class MyEntity extends GenericPersistableEntity implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
MyEntityPrimaryKeys id;//Composite Primary key
//Composite fields can be declared here for getter and setters
#Column(name = "ROLLNO")
private Long RollNo;
//Composite fields can be declared here for getter and setters
#Column(name = "AGE")
private Long age;
#Column(name = "OtherFields"
private Long OtherFields;
//getter and setters comes here
}
#Embeddable
class MyEntityPrimaryKeys implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name = "ROLLNO")
Long RollNo;
#Column(name = "AGE")
Long age;
#Override
public int hashCode() {
HashCodeBuilder hcb = new HashCodeBuilder();
hcb.append(RollNo);
hcb.append(age);
return hcb.toHashCode();
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof MyEntityPrimaryKeys)) {
return false;
}
MyEntityPrimaryKeys that = (MyEntityPrimaryKeys) obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(RollNo, that.RollNo);
eb.append(age, that.age);
eb.append(tonMonth, that.tonMonth);
eb.append(tonYear, that.tonYear);
return eb.isEquals();
}
}