I found similar questions, but they did not answer my question.
I have two entities with a many-to-one relationship - unidirectional.
But most importantly, the relationship is lazy. Because it is correct to use a lazy connection, everyone knows it.
Code:
#Entity
public class User implements BaseEntity {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#ManyToOne(fetch = FetchType.LAZY)
private City city;
}
#Entity
public class City implements BaseEntity {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
}
interface BaseEntity {
void setId(Long id);
Long getId();
}
I wrote a method that allows you to search by the transferred fields of the entity.
An example of how this works:
public class Search<T extends BaseEntity> {
public List<T> getByFields(T entity, List<FieldHolder> data) {
// create criteria with passed field name and value by reflection
}
}
class FieldHolder {
private String fieldName;
private Object value;
/**
* "true" - means that the field "value" contains id related object
* "false" - elementary type like: String, Wrapper, Primitive
*/
private boolean isRelationId;
}
The problem is that problems start when you need to search and related objects - by creating related queries.
The following entry is used to send the associated field: "city.id" and the problem is that when I transfer the essence of the related object (City) it is in a proxy and I cannot get id by reflection from City.
My function works perfectly if you specify:
#ManyToOne(fetch = FetchType.EAGER)
private City city;
But it will greatly affect performance, since I have a lot of related objects. Therefore, I want to solve this problem for a lazy load.
I know that this is not an easy task. But perhaps there is some opportunity to somehow get around this problem.
Related
I have an entity EncodingResult that references three others. I want to find out how to use the repository's findBy() methods to return an entity based on its foreignKey so that I can, for example, make a GET request passing a Video's foreign key as a parameter and return whether or not there is an EncodingResult containing a Video with the given foreignKey.
How would you go about doing this? I tried reading a bit on EntityGraphs and was rather confused. There also doesn't seem to be a great number of content explaining these parts of the framework.
It would be better if you posted the code for your entities, but from your description, I think you have something like this:
#Entity
public class EncodingResult {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(mappedBy = "encodingResult")
private List<Video> videos=new ArrayList<Video>();
//...boilerplate
}
#Entity
public class Video {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
#ManyToOne
EncodingResult encodingResult;
//...boilerplate
}
So you can define findBy methods in your EncodingResultRepository like so.
public interface EncodingResultRepository extends JpaRespository<EncodingResult, Integer> {
public Optional<EncodingResult> findByVideoName(String name);
public Optional<EncodingResult> findByVideoId(Integer id);
}
In my spring data project, there is an entity that looks like:
public class Employee {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="id")
private Integer id;
#Column(name="category")
private Category category;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="element_id")
private Department department;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="agency_id")
private Agency agency;
public Employee() {}
// routine getters and setters
}
In my EmployeeRepository, I find that I can derive a method, findEmployeeById() that seems to work in exactly the same way as the usual findById() (but I'm not sure). Can someone explain the difference between these two methods?
Optional<Employee> findEmployeeById (Integer id);
vs
Optional<Employee> findById (Integer id);
I "discovered" this by accident via autocomplete in my side (IntelliJ).
The difference is that while findEmployeeById() searches - as it states - employee by its field named id, findById searches by field annotated as #Id disregarding what is the name of the entity's id field.
In your case - as with many else's - the thing is that the #Id field happens to be named id so the result is the same.
I'm writing backend for a cms of sorts that needs to support having different versions of its entities and also the ability to choose which of the versions is the current/active one. I've looked around on this site and others and found some advice on implementing versioning (which I've taken to heart) but nothing in terms of "version switching", as I call it.
My question is twofold, I suppose:
1) I want to know if there is any (preferably open-sourced) system that does something similar? Are there any design patterns that are related to what I'm doing?
2) I would appreciate a review of my implementation below.
Here's a rundown of my entities:
Firm:
#Entity
public class Firm {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne
#JoinTable(name = "firm_firm_version")
private FirmVersion firm;
FirmVersion:
#Entity
public class FirmVersion {
#EmbeddedId private FirmVersionId id;
private String name;
#ManyToMany(mappedBy = "firmVersion")
private List<Staff> staff = new ArrayList<>();
FirmVersionId:
#Embeddable
public class FirmVersionId implements Serializable {
private Long id;
private Integer version;
}
FirmStaff:
#Entity
public class FirmStaff {
#Id #GeneratedValue
private Long id;
#ManyToMany
private List<FirmVersion> firmVersion = new ArrayList<>();
private String name;
// ...fields
}
This works fine, but my main concern is the propagation of these #ManyToMany relations. The way I implemented it, every time you update a staff you create 1) a new staff and 2) a new FirmVersion and however many table rows it takes to link them, which I imagine can get out of hand pretty quickly.
It took me hours to realize, what the problem is:
I have a Spring Rest service and a GET-Method which returns a user in JSON-Format.
The data comes from my database over sessionFactory.
After debugging it turned out, that the Problem is related to my bidrectional onetomany-manytoone relationship.
So calling
User user = (User) sessionFactory.getCurrentSession().load(User.class, userId);
returns a User-Object where user.getCity().getSupplier() runs into an com.sun.jdi.InvocationException. Therefore Jackson is obviously unable to serialize.
But what causes this exception?
#Entity
#Table(name = "T_CITY")
public class City implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long id;
#OneToMany(mappedBy = "city", cascade=CascadeType.ALL)
private Set<User> user;
#OneToMany(mappedBy = "city", cascade=CascadeType.ALL)
private Set<Supplier> supplier;
User:
#Entity
#Table(name = "T_USER")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
public User() {
}
#Id
private long id;
#ManyToOne
private City city;
Supplier:
#Entity
#Table(name = "T_SUPPLIER")
public class Supplier implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long id;
#ManyToOne
private City city;
As mentioned in the other answer, I think you'll find that your issues are related to the x-to-x relationships. This can sometimes create circular reference issues when trying to jsonify the entity beans.
Sometimes you can avoid or get past this by using annotations, other times a wrapper class is needed. I often just write a wrapper class to handle my JSON transactionts
There are many many references to this type of issues spanning many languages. Here a few starting points for you to research.
Google related search regarding circular references in entity objects
Json and Java - Circular Reference
Circular Dependencies With Jackson
Lets assume we have the following situation:
We want to inherit all the values of the class Articles except one it's name for instance. How can we achieve it? I know that if we want to inherit everything from the Articles just write
public class Fruits extends Articles{ ... }
but how can we manage to inherit only specific attributes of the class Articles, ie. every attribute except one and one attribute leave intact?
EDIT:
#Entity
#Table(name = "Article")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Article {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Basic(optional = false)
#Column(name = "ART_ID")
private Long id;
#Basic(optional = false)
#Column(name = "ART_NAME")
private String name;
#Basic(optional = true)
#Column(name = "ART_COST")
private String cost;
// ...
}
#Entity
#Table(name="Fruits")
#AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="ART_NAME")),
#AttributeOverride(name="cost", column=#Column(name="ART_COST")),
})
// This is what is causing the issue. Fruits inherits something which is already defined in it's scope, and as the result can't declare exactly how to process it.
public class Fruits extends Article {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Basic(optional = false)
#Column(name = "FRU_ID")
private Long fruitID;
#Column(name="FRU_FROZEN")
private String fruFrozen;
//...
}
So, I think code won't work, because this will result in multiple IDs in the entity hierarchy, so is there any other way I can solve this?
You can't remove a member from Articles
When name is a member of Articles and Fruits IS A Articles,
there could not be a way to remove name
You may hide some members from Articles using scope private
An other approach is to create a class "BaseArticles" without the member name.
Then derive both Articles AND Fruits from BaseArticles
public BaseArticles {
// HAS NO private String name;
...
}
public Article extends BaseArticles {
private String name;
...
}
public Fruits extends BaseArticles {
// WITHOUT private String name;
...
}
However, it is not simple but possible to deal with OO-inheritance using hibernate.
There is an annotation but I do not know off hands
You can put base class not required attribute as a private.