I was wondering if it was possible to not need the #Query annotation and let Spring Data construct the JPA Query based on my method name and method parameters for the below entity relationship. I want to retrieve a list of ItemLocations that are related to a particular Item. I tried the below signature and it didn't work without the #Query. Is it also more proper (efficient/effective) to pass in the Item.id instead of the Item object itself?
Spring Data Version: 1.3.4.RELEASE
Working Spring Data Repository API:
#Query("FROM ItemLocation where item = ?")
public List<ItemLocation> getAllItemLocations(Item item);
Desired Spring Data Repository API:
public List<ItemLocation> findAllItemLocations(Item item);
JPA Enties:
#Entity
public class ItemLocation {
#ManyToOne
#JoinColumn(name="fk_item_id")
public Item getItem() {
return this.item;
}
public void setItem(Item item) {
this.item = item;
}
#Id
#GeneratedValue
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
private Item item;
private long id;
}
#Entity
public class Item {
#OneToMany(mappedBy="item", orphanRemoval=true)
#Cascade({org.hibernate.annotations.CascadeType.PERSIST})
public Set<ItemLocation> getItemLocationList() {
return this.itemLocationList;
}
public void setItemLocationList(Set<ItemLocation> list) {
this.itemLocationList = list;
}
#Id
#GeneratedValue
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
private Set<ItemLocation> itemLocationList
= new HashSet<ItemLocation>();
private long id;
}
public List<ItemLocation> findAllByItem(Item item);
(in repository ItemLocationRepository)
Related
is there a way in mapstruct to ignore the case of the fields when mapping. let say i want to map following two classes
public class Customer {
private String ID;
public String getID() {
return ID;
}
public void setID(String iD) {
this.ID = iD;
}
}
public class CustomerDetails {
private String id;
public String getId() {
return ID;
}
public void setId(String id) {
this.id = id;
}
}
MapStruct is not automatically mapping the fields because getter methods names that doesn't match. Is there a way to configure MapStruct to ignore the case of the fields and map them automatically
A custom AccessorNamingStrategy can be implemented that would lowercase the element name and thus making it case insensitive.
e.g.
public class CaseInsensitiveAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
#Override
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
return super.getPropertyName( getterOrSetterMethod ).toLowerCase( Locale.ROOT );
}
#Override
public String getElementName(ExecutableElement adderMethod) {
return super.getElementName( adderMethod ).toLowerCase( Locale.ROOT );
}
}
Not sure if you can configure mapstruct to map case insensitive but you always can define what should be mapped like this:
#Mapping(source = "ID", target = "id")
CustomerDetails toCustomerDetails(Customer customer);
I'm creating a simple web store as part of a larger application, using Spring Boot and Spring Data JPA. I have a number of items (my stock), and an order will consist of a collection of those items (along with shipping information, etc).
It's possible that items in the stock will update - for example, changing the price. I want to be able to do this without the overhead of versioning, etc. However, when I look up past orders I want to get the information that was used at the time.
Is there a way in Spring Data JPA of embedding a copy of the item in my order, rather than linking to the item object?
My classes are below:
ShopItem.java
#Entity
public class ShopItem {
#Id
#GeneratedValue
private Long id;
private String name;
private String description;
private int price;
private int stock;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
this.stock = stock;
}
public void reduceStock(int by){
this.stock = this.stock - by;
}
}
ShopOrder.java
#Entity
public class ShopOrder {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private Member member;
private boolean postage;
#OneToMany
private List<ShopOrderItem> items;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Member getMember(){
return member;
}
public void setMember(Member member) {
this.member = member;
}
public boolean getPostage() {
return postage;
}
public void setPostage(boolean postage) {
this.postage = postage;
}
public List<ShopOrderItem> getItems() {
return items;
}
public void setItems(List<ShopOrderItem> items) {
this.items = items;
}
}
ShopOrderItem.java
#Entity
public class ShopOrderItem {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private ShopItem item;
private int quantity;
public ShopOrderItem(ShopItem item, int quantity){
this.item = item;
this.quantity = quantity;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ShopItem getItem() {
return item;
}
public void setItem(ShopItem item) {
this.item = item;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getTotalPrice(){
return item.getPrice() * quantity;
}
}
Spring Data JPA is only a way to make your life easier when you use an ORM. and a ORM is only a way to make your life easier when you use a Database.
The thing is, if you are using a relational Database, there is no way to do what you want except by cloning datas.
so, one way is to clone your ShopItem entity and store it as a new entry in your database in a dedicated table.
another way may be to use a NoSQL DB which could handle this better.
There is a number of different ways to store a history of orders, but I can't think of anything from Spring data JPA which could do it out of the box.
Please help me to understand why hibernate field based annotation works based on the primarykey field?.
Model Class 1 takes docnum field value from getter and Model Class 2 too.Inspite of both places only docnum is annotated based on the getter only.It works based on id field which is having annotaion in field of Model Class 2 and in Model Class 1 based on getter.
Model Class 1:
#Entity(name="RDT_ORDER")
public class Order {
private int id;
private String docnum;
#Id
#Column(name="ORDID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name="ORD_DOCNUM")
public String getDocnum() {
return docnum+" getter";
}
public void setDocnum(String docnum) {
this.docnum = docnum;
}
}
Model Class 2:
#Entity(name="RDT_ORDER")
public class Order {
private int id;
private String docnum;
#Id
#Column(name="ORDID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name="ORD_DOCNUM")
public String getDocnum() {
return docnum+" getter";
}
public void setDocnum(String docnum) {
this.docnum = docnum;
}
}
Output :table(RDT_ORDER) values
ID DOCNUM
5 docnum5
6 docnum6 getter
I have an object similar to the following:
public class FooObj
{
private Long id;
private List<BarObj> subBar;
private String someStr;
public Long getId()
{
return id;
}
public List<BarObj> getSubBar()
{
return subBar;
}
public String getSomeStr()
{
return someStr;
}
public void setId(Long id)
{
this.id = id;
}
public void setSubBar(List<BarObj> subBar)
{
this.subBar = subBar;
}
public void setSomeStr(String someStr)
{
this.someStr = someStr;
}
public static class BarObj
{
private String groupId;
private Long id;
public String getGroupId()
{
return groupId;
}
public Long getId()
{
return id;
}
public void setGroupId(String groupId)
{
this.groupId = groupId;
}
public void setId(Long id)
{
this.id = id;
}
}
}
And I want to map the Object to an XML structure like the XML in the link: http://pastebin.com/cw018jqc EDIT:(Please look at the ObjBars element for an exact definition of what I'm looking for.)
Is there any library available that would allow me to do this?
So you're basically trying to split a list into multiple sublists before you serialize it to XML? I think that JAXB could really help you here. I think you could use an #XmlTypeAdapter to convert between List<BarObj> and List<List<BarObj>>, which would be one way of representing this data the way you want it marshalled to XML. Check out http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html for details.
I am learning Hibernate and just read the chapter "7.2.3 Adding columns to join tables" of the "Java Persistance with Hibernate" book. My goal is to save Item, Category and CategorizedItem in one transaction.
There is a constructor there (page 305):
public CategorizedItem(String username, Category category, Item item) {
// Set fields
this.username = username;
this.category = category;
this.item = item;
// Set identifier values
this.id.categoryId = category.getId();
this.id.itemId = item.getId();
// Guarantee referential integrity
category.getCategorizedItems().add(this);
item.getCategorizedItems().add(this);
}
It accepts category and item objects. If I create a Category and an Item and want to connect them with this technique, they obviously have to be persisted BEFORE, as category.getId() and item.getId() return null.
Is there "a trick in the Hibernate bag" that can cascade the saving of a join table? The join table have additional columns. I want to save all three objects in the onSuccess handler in my web page controller. All three entities or none of them must be inserted.
You said
My goal is to save Item, Category and CategorizedItem in one transaction
Is there a trick in the Hibernate bag that can cascade the saving of a join table ?
Yes, use MutableInt
#Entity
public class CategorizedItem implements Serializable {
private CategorizedItemId categorizedItemId;
private String userName;
private Category category;
private Item item;
/**
* required no-arg constructor
*/
public CategorizedItem() {}
public CategorizedItem(CategorizedItemId categorizedItemId) {
this.categorizedItemId = categorizedItemId;
}
public CategorizedItem(String userName, Category category, Item item) {
this.userName = userName;
this.categorizedItemId = new CategorizedItemId(category.getIdAsMutableInt(), item.getIdAsMutableInt());
}
#EmbeddedId
public CategorizedItemId getCategorizedItemId() {
return this.categorizedItemId;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="CATEGORY_ID", insertable=false, updateable=false)
public Category getCategory() {
return this.category;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ITEM_ID", insertable=false, updateable=false)
public Item getItem() {
return this.item;
}
// setter's goes here
/**
* It MUST implements Serializable
* It MUST overrides equals and hashCode method
* It MUST has a no-arg constructor
*
* Hibernate/JPA 1.0 does not support automatic generation of compound primary key
* You SHOULD set up manually
*/
#Embeddable
public static class CategorizedItemId implements Serializable {
private MutableInt categoryId = new MutableInt(-1);
private MutableInt itemId = new MutableInt(-1);
/**
* required no-arg constructor
*/
public CategorizedItemId() {}
public CategorizedItemId(MutableInt categoryId, MutableInt itemId) {
this.categoryId = categoryId;
this.itemId = itemId;
}
#Column(name="CATEGORY_ID", updateable=false, nullable=false)
public Integer getCategoryId() {
return this.categoryId.intValue();
}
public void setCategoryId(Integer categoryId) {
return this.categoryId.setValue(categoryId);
}
#Column(name="ITEM_ID", updateable=false, nullable=false)
public Integer getItemId() {
return this.itemId.intValue();
}
public void setItemId(Integer itemId) {
return this.itemId.setValue(itemId);
}
// getter's and setter's
#Override
public boolean equals(Object o) {
if(!(o instanceof CategorizedItemId))
return null;
finalCategorizedItemId other = (CategorizedItemId) o;
return new EqualsBuilder().append(getCategoryId(), other.getCategoryId())
.append(getItemId(), other.getItemId())
.isEquals();
}
#Override
public int hashCode() {
return new HashCodeBuilder().append(getCategoryId())
.append(getItemId())
.toHashCode();
}
}
}
Here goes Category
#Entity
public class Category implements Serializable {
public MutableInt id = new MutableInt(-1);
private List<CategorizedItem> categorizedItemList = new ArrayList<CategorizedItem>();
#Transient
public MutableInt getIdAsMutableInt() {
return this.id;
}
#Id
#GeneratedValue
public Integer getId() {
return this.id.intValue();
}
public void setId(Integer id) {
return this.id.setValue(id);
}
#OneToMany(mappedBy="category")
#JoinColumn(name="CATEGORY_ID", insertable=false, updateable=false)
#Cascade(CascadeType.SAVE_UPDATE)
public List<CategorizedItem> getCategorizedItemList() {
return categorizedItemList;
}
// setter's
/**
* Use this method when you have a saved Item
*/
public void addCategorizedItem(CategorizedItem categorizedItem) {
categorizedItem.setCategorizedItemId(new CategorizedItemId(getIdAsMutableInt(), categorizedItem.getItem().getIdAsMutableInt()));
categorizedItem.setCategory(this);
getCategorizedItemList().add(categorizedItem);
}
}
And Item
#Entity
public class Item implements Serializable {
public MutableInt id = new MutableInt(-1);
private List<CategorizedItem> categorizedItemList = new ArrayList<CategorizedItem>();
#Transient
public MutableInt getIdAsMutableInt() {
return this.id;
}
#Id
#GeneratedValue
public Integer getId() {
return this.id.intValue();
}
public void setId(Integer id) {
return this.id.setValue(id);
}
#OneToMany(mappedBy="item")
#JoinColumn(name="ITEM_ID", insertable=false, updateable=false)
#Cascade(CascadeType.SAVE_UPDATE)
public List<CategorizedItem> getCategorizedItemList() {
return this.categorizedItemList;
}
// setter's
/**
* Use this method when you have a saved Category
*/
public void addCategorizedItem(CategorizedItem categorizedItem) {
categorizedItem.setCategorizedItemId(new CategorizedItemId(getIdAsMutableInt(), categorizedItem.getCategory().getIdAsMutableInt()));
categorizedItem.setItem(this);
getCategorizedItemList().add(categorizedItem);
}
}
Now because you need categoryId and itemId before saving CategorizedItem, do as follows
Category category = new new Category();
Item item = new Item();
session.save(new Category());
session.save(new Item());
session.save(new CategorizedItem(userName, category, item));
Notice the cascading just works when you have either a saved Category or a saved Item. Otherwise, you need to follow the approach shown above