App engine with Objectify data structure - java

Really like objectify, although still struggling with what is the best way to structure my data in my app. I will be launching a new app soon and do not want to get stuck with a structure that may not function right, or would perform very slowly.
The app will be on the HRD and will have a large number of entity types. For illustrative purposes I will make up some example entities. Suppose the app is for fast food restaurants. Each chain will be an entity(for example McDonalds, Wendy's, etc.). Each specific franchise or location will be an entity as well. Employees, Orders, Menus, Timesheets, and so on will also be entities.
I guess by biggest question is how to setup the relationships between these entities? I have been store relationships by storing the datastore ID as a long in each entity. For example each employee entity would have a long value that is the datastore ID for the location they work at, as well as for which chain they are a member of.
With this structure I can query for all of the orders from a specific restaurant with a statement such as:
Long restaurantId =restaurant.getId();
Query<Order> q=ofy.query(Order.class).filter("location", resturantId);
Just curious if there is any issue with using the datastore/objectify in this manner. Any input would be great! I have been using something similar on a small scale and seems to work fine. Ideally I would like the most efficient structure, and i realize this may take some testing. However once may app is deployed it may be very difficult to change...
#Entity
public class Chain {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String type;
//getters & setters, etc
}
#Entity
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long chain; //which resturant chain the location belongs to (mcdonalds, wendy's, etc)
private String address;
private String owner;
private String phoneNumber;
//getters & setters, etc
}
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long location; //which location the employee works for
private Long chain; //which resturant chain the location belongs to (mcdonalds, wendy's, etc)
private String name;
private String position;
//getters & setters, etc
}
#Entity
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long chain; //which resturant chain the location belongs to (mcdonalds, wendy's, etc)
private Long location;
private Long employee; //employee that took order
private Order order;
private String time;
//getters & setters, etc
}

This is standard practice. Go forth!
Objectify is great - we've been using it for about 6 months and we're very happy with it.

Key<Object> is type safe, Long is not. Using Long is discouraged in the documentation.
Reference: https://github.com/objectify/objectify/wiki/Entities#relationships
I'd encourage you to read through that entire page, it's worth the time. I now have a type-safe structure using Ref<Object> everywhere.

Related

Design review: Spring JPA entity versioning with "version switching"

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.

How to get the value of the lazy Hibernate field through reflection

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.

JPA Hibernate :: Inheritance of an entity, with additional OneToMany Lists

I'm using JPA Hibernate/Spring boot to build a web server with MySQL database, and I'm trying to extend a POJO Entity that looks like this, with additional OneToMany Lists.
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue
private Integer id;
#Column(nullable=false)
private String name;
....Constructors, getters and setters....
}
with this basic user entity, I just wanna make a UserInfo entity with additional information about the user's careers.
#Entity
public class UserInfo extends User {
#OneToMany(cascade= CascadeType.ALL, fetch= FetchType.EAGER)
#JoinColumn(name="user_id", referencedColumnName = "id")
private List<Career> careers;
....Constructors, getters, setters......
}
And I'm quite confused which inheritance strategy I should choose. I don't think its necessary to make another column or table for this.
Or should I just query twice..?
I'm kinda new to JPA so not sure which is considered as the best practice or design..
Edit:
This is how Career entity looks like. Just in case..
#Entity
#Table(name="career")
public class Career {
#Id
#GeneratedValue
private Integer id;
#Column(nullable=false)
private Integer user_id;
#Column(nullable=false)
private String name;
#Column(nullable=false)
private String description;
....Constructors, getters and setters....
}
Since extending User table was meaningless(just in my case), I changed the User class like this.
#Table(name="user")
public class User {
#Id
#GeneratedValue
private Integer id;
#Column(nullable=false)
private String name;
#OneToMany(fetch= FetchType.LAZY)
#JoinColumn(name="user_id", referencedColumnName = "id")
private List<Career> careers;
....Constructors, getters, setters......
}
Now I'm trying this with Spring Data JPA, and when I try to show the list of Users with their Careers, it is now querying more than 40 times taking about a minute to show the result.
Is this the N+1 problem..? how can I solve this?
In my opinion the error lies within the model itself. Why should UserInfo extend User? I cannot imagine which attributes or methods the UserInfo should inherit from a User. Typical inheritances would be "Developer" or "Administrator".
Why don't you add UserInfo as a 1:1 relation in your User entity? Another option is to omit UserInfo and put the Careers as a 1:n relation right into your User.
To prevent possible n+1 issues on a growing number of Careers you might want to change the fetch mode. See below
#OneToMany(fetch=FetchType.LAZY,mappedBy="user")
#Fetch(FetchMode.SUBSELECT)
private Set<Career> careers = new HashSet<>();

When to use one to many or many to one in JPA

Lets say I'm developing a polling app like strawpoll.me. Would it be best to create my poll bean to contain a list of options or options to have a many to one relationship with a single poll? Also, when submitting the form to create a poll, does the database know to assign the foreign key in the OPTION table to the POLL_ID of the poll they belong to automatically? I know JPA makes database interactions simple but I cant find any examples that add objects with a one to many/many to one relationship at the same time.:
#Entity
#Table(name="POLL")
public class Poll implements Serializable{
#Id
#Column(name="POLL_ID")
#GeneratedValue
private int id;
#Column(name="QUESTION_TEXT")
private String question;
#Column(name="CREATED_ON")
private Timestamp dateCreated;
#OneToMany
#JoinColumn(name="OPTION_ID")
private List<Option> options = new ArrayList<Option>();
}
#Entity
#Table(name="OPTION")
public class Option implements Serializable{
#Id
#Column(name="OPTION_ID")
#GeneratedValue
private int id;
#Column(name="OPTION_TEXT")
private String optionText;
#Column(name="NUM_OF_VOTES")
private int numOfVotes;
}
Or set up like this:
#Entity
#Table(name="POLL")
public class Poll implements Serializable{
#Id
#Column(name="POLL_ID")
#GeneratedValue
private int id;
#Column(name="QUESTION_TEXT")
private String question;
#Column(name="CREATED_ON")
private Timestamp dateCreated;
}
#Entity
#Table(name="OPTION")
public class Option implements Serializable{
#Id
#Column(name="OPTION_ID")
#GeneratedValue
private int id;
#ManyToOne
#Column(name="POLL_ID")
private Poll poll;
#Column(name="OPTION_TEXT")
private String optionText;
#Column(name="NUM_OF_VOTES")
private int numOfVotes;
}
(As I think there are room for improvement for the other 2 answers, I am giving mine)
What you are trying to do is actually quite common. It is normally referred as Bi-directional one-to-many relationship. In your case it should look like:
class Poll {
//....
#OneToMany(mappedBy="poll")
private Set<Option> options;
}
class Option {
//...
#ManyToOne
#JoinColumn("poll_id") // I always like to be explicit on naming :P
private Poll poll;
}
This gives you a more intuitive model. It allow you to navigate from both sides (e.g. in HQL).
One confusion is usually: which side Hibernate is going to use to maintain the relationship in DB? In Hibernate, there should be one side "owning" a relationship (what we shown above is one relationship, though bi-directional). If you have #JoinColumn in both side, Hibernate will complain. In our above example, by using mappedBy, Hibernate knows that it is the Option side owning the relationship. You can see the difference if the Poll side and Option side is inconsistent (e.g. You have Poll-1 containing Option-1, but Option-1 pointing to Poll-2, and Poll-2 is not containing Option-1. The result is, the Option table will be referring Poll-2)
Some pitfalls you should be aware. What is described above about "owning relationship" is simply on the ORM aspect. If you do not properly maintain your relationships in your model, your models may become inconsistent and will have problem if you are changing them in same session. It is your obligation to make sure the relationship is consistent.
It must be:
#Entity
#Table(name="POLL")
public class Poll implements Serializable{
#Id
#Column(name="POLL_ID")
#GeneratedValue
private int id;
#Column(name="QUESTION_TEXT")
private String question;
#Column(name="CREATED_ON")
private Timestamp dateCreated;
#OneToMany(mappedBy="poll")
private List<Option> options;
}
#Entity
#Table(name="OPTION")
public class Option implements Serializable{
#Id
#Column(name="OPTION_ID")
#GeneratedValue
private int id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="POLL_ID")
private Poll poll;
#Column(name="OPTION_TEXT")
private String optionText;
#Column(name="NUM_OF_VOTES")
private int numOfVotes;
}
JPA knows what table hooks up to it by entity name. If you have an Option entity, and your Poll entity contains a List<Option>, then JPA knows how to map one to another.
You DO NOT have to manage both sides of the relationship; if you add an Option to your Poll and persist the Poll, the Option will be updated as well. You don't have to go into the Option to set its Poll, so long as you're refreshing the Option from your data source before you use it again.
I prefer to manage the Many-to-One side, as it is less complicated on a case-by-case basis to tell a child entity which parent it belongs to. Otherwise, for example, adding a new entry to a Set<Option> would require the whole Set to be retrieved from the data source (for the purposes of comparing whether the set already contains it), while telling the Option which Poll it belongs to only needs to update one object.

RMI+hibernate,how can client get generated id

#Entity
public class Record implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#OneToMany(fetch=FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#Cascade(value={CascadeType.SAVE_UPDATE})
private List<Comment> commentList=new ArrayList<Comment>();
}
#Entity
public class Comment implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(columnDefinition="text")
private String content;
}
I have a Record in my Client, and add SOME comments in the list. Use the RMI method: void update(Record reocord).Then at the Server, hibernate save Comments with id=0 into database, and give a generated id.How can I assign these IDs to Comments in the Client? If not, the other time I call update(Record reocord), Comments will be add twice. Maybe: Record update(Record reocord), but I think if Record have large data it's not wise.
I faced this issue. If you are autogenerating the primary key (which can be mostly used for normalizing tables), Create a unique Id yourself based on the existing data. Do remember to override hashcode and equals for comparison purposes.

Categories

Resources