JDBC Domain Design and Relationships - java

I've used Hibernate / JPA in the past, now using a combination of Spring JDBC and MyBatis.
With JPA/ Hibernate if you had a Customer, which had an address you would have a domain structure similar to code below. (minus all the annotations / config / mappings).
Does this still make sense when using JDBC or MyBatis. This is composition domain design from what I know, has-a, belongs-to, etc. However most examples I've seen of JDBC code they have domain object that bring back the IDs rather than collection, or flatten the data. Are there any performance benefits from either approach, maintainability, etc. Having worked with JPA first I'm not sure what the JDBC way of doing things are.
public class Customer {
private Long id;
private String userName;
private String password;
private String firstName;
private String lastName;
private Collection<Address> addresses
...
}
public class Address {
private Long id;
private String streetAddress1;
private String streetAddress2;
private String city;
private State state;
private String postalCode;
}
public class State {
private Long id;
private String code;
private String name;
private Country country;
}
public class Country {
private Long id;
private String code;
private String name;
}
I come across an example and here was one of their classes.
public class Question {
private long questionId;
private long categoryId;
private long userId;
private long areaId;
private String question;
private String verifyKey;
private Date created;
private User user;
private List<Answer> answers;
private long answerCount;
private String name;
// getters and setters omited...
}
Why would you fetch the userId, areaId, and categoryId instead of actually fetching the associated object? The ID is likely of no use to the front end user, I suppose you could use the ID to issue another query to fetch additional data, but seems inefficient making another round trip to the database.

You can look at this domain object as a "footprint" of database table. In your example, userId, areaId and categoryId from Question are most likely foreign keys from corresponding tables. You could never need full object data in the moment of Question creation and retrieve it later with separate db request. If you fetch all associated objects at once, you will hit at least one additional table per object (by join-s or subselect-s). Moreover, that's actually the same that Hibernate does. By default, it loads domain object lazily and hits database again if uninitialized associated object is needed.
At that time, it is better to fetch those objects that a domain object can't exist without. In your example, Question and List are coupled.
Of course, if you need user, or category, or any other associated object again in some another place of application (assume the reference to previously retrieved object has been lost), you will hit the database with same query. It should be done and could seem inefficient, because both plain JDBC and SpringJDBC have no intermediate caching unlike Hibernate. But that's not the purpose JDBC was designed for.

Related

Question about Springboot, mongoDB relations and API

So I'm trying to create a project based in some weather forecast API and the data comes in different objects like:
public class WeatherForecast{
private String local;
private int maxTemp;
private int minTemp;
private int precipitationId;
}
public class Precipitation{
#Id
private int id;
private String descriptionEn;
private String descriptionCh;
...
}
So, I want to store this information and obtain the description of the Precipitation in the language that I desire, without receiving an WeatherForecast with the description of 10+ languages.
I searched a lot about defining relations between the tables but I couldn't find something related to relationships by id's. I found that I could use,
#DbRef
private Precipitation precipitation;
but I couldn't understand how it can interpret the Id without passing in the constructor.
And, finally, I want to understand if it's a good practice to send the two objects
separately to the database and try to workout some functionality to get the object I want, something like this:
public class WeatherForecast{
private String local;
private int maxTemp;
private int minTemp;
private String description;
}
using criteria, queries, or other things without extracting the two tables and searching in Precipitations for the desired description language.

Java JPA enum-like String options

I am trying to implement a simple User-Roles relationship in a Spring application, for security. The basic entities (some fields and annotations trimmed):
User
#Table(name="usr")
public class User implements Serializable {
#Id
private UUID id;
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="user_roles", joinColumns=#JoinColumn(name="user_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="role_id", referencedColumnName="id"))
private Collection<Role> roles;
}
Role
public class Role implements Serializable {
#Id
private UUID id;
#ManyToMany(mappedBy="roles")
private Collection<User> users;
private String name;
}
So far, so good. However, I also have a class that defines a list of role-name values:
UserRoles
public class UserRole {
public static final String ADMIN = "admin";
public static final String USER = "user";
}
I want to constrain the values of the Role's name field to the values in UserRoles, effectively like an enum.
These role values will get used within Spring Security functions that require roles to be string values. As such, if I were to make UserRoles an enum, any database storage would be of ints – the ordinal definition position within UserRoles – which would force me to keep any potentially deprecated options, and also require a hacky conversion every time I need to convert the role to a string that can be passed around in a JWT, etc. (If I want to look at my database directly, it will also be far less informative.)
Is there some way to define Role's name field as limited to the static values in UserRoles? (Changing how or where these values are stored is entirely acceptable.)
You can define like this
public enum UserRoleEnum {
USER, ADMIN
}
And in entity
#Enumerated(EnumType.ORDINAL)
private UserRoleEnum role;

Web application spring boot and angular 5

I am making a simple CRUD application using Spring boot and MongoDB, the problem that I am facing is that I don't know how to define the model classes.
My application should be like this:
A site has some characteristics such as an ID, region, city, ... and contains 4 parts (cellulars) that each has its own characteristics. Any help would be appreciated.
This is what I have so far:
public class Site {
#Id
String siteId;
String projectPhase;
String region;
String city;
String siteName;
String newSiteName;
String clusterName ;
String longitude ;
String lattitude ;
#OneToMany(mappedBy = "siteId")
List L;
What I want to know is how do I associate another class inside this one.
Annotations like #OneToMany are typically used within JPA-context, and are unnecessary when using Spring Data MongoDB. This is also mentioned by the documentation:
There’s no need to use something like #OneToMany because the mapping framework sees that you want a one-to-many relationship because there is a List of objects.
You have a few options when you want to define one-to-many relations when using MongoDB. The first of them is to define them as embedded objects within the same document:
#Document
public class Site {
#Id
private String id;
private String city;
private String region;
private List<Part> cellulars;
}
public class Part {
private String characteristic1;
private String characteristic2;
}
This means that the parts do not exist on their own, so they don't need their own ID either.
Another possibility is to reference to another document:
#Document
public class Site {
#Id
private String id;
private String city;
private String region;
#DBRef
private List<Part> cellulars;
}
#Document
public class Part {
#Id
private String id;
private String characteristic1;
private String characteristic2;
}
In this case, parts are also separate documents, and a site simply contains a reference to the part.

OrientDB: delete record and references created with Object API

I am using the OrientDB 2.1.6 Object API.
I have two POJOs with a 1 to N relationship like this:
public static class Results {
private String userId;
private String templateId;
private Double totalLength;
private List<String> visibleFields;
private Boolean filterable;
#OneToMany(orphanRemoval = true)
private List<ResultItem> items;
//Generic getters and setters
}
public static class ResultItem {
private String id;
private String vsId;
private String entryTemplateId;
private String objectType;
private String objectTypeLabel;
private String capabilityComment;
private Boolean currentVersion;
private Double contentSize;
private String name;
private String objectStoreId;
private String mimeType;
private HashMap<String, String> attributes;
private Date dateLastModified;
//generic getters and setters
}
This creates two classes in OrientDB. If I delete a Results instance using the Object API, it will delete associated ResultItem rows correctly.
I am trying to delete a particular ResultItem record using the "console" like this:
orientdb {db=test}> find references #15:6392 Found
[{rid:#15:6392,referredBy:[1]}] in 0.014000 sec(s).
orientdb {db=test}> delete from ResultItem where #rid=#15:6392 Delete
record(s) '1' in 0.006000 sec(s).
orientdb {db=test}> find references #15:6392 Found
[{rid:#15:6392,referredBy:[1]}] in 0.014000 sec(s).
The console output suggests that the record has been deleted but it continues to contain a "reference".
This manifests itself as a problem when I go back to the Object api and try to db.detachAll(results, true);. It throws this exception which I assume is due to the the orphan relationship.
Caused by: java.lang.NullPointerException
at com.orientechnologies.orient.object.db.OObjectLazyList.convertAndDetachAll(OObjectLazyList.java:456)
at com.orientechnologies.orient.object.db.OObjectLazyList.convertAndDetachAll(OObjectLazyList.java:432)
at com.orientechnologies.orient.object.db.OObjectLazyList.detachAll(OObjectLazyList.java:424)
at com.orientechnologies.orient.object.enhancement.OObjectProxyMethodHandler.detachAll(OObjectProxyMethodHandler.java:165)
at com.orientechnologies.orient.object.enhancement.OObjectEntitySerializer.detachAll(OObjectEntitySerializer.java:261)
at com.orientechnologies.orient.object.db.OObjectDatabaseTx.detachAll(OObjectDatabaseTx.java:809)
at com.orientechnologies.orient.object.db.OObjectDatabaseTx.detachAll(OObjectDatabaseTx.java:327)
How can I delete the relationship along with the record?
I tried your case and I got your same results.
This is a limitation about the references because there's no check on #RID consistency and when you delete a document, the deletion of all references would activate a full scan of the DB to search all the documents linked to the first and then drop the references.
This would be a very expensive operation and it would take a lot of time, this is one the reasons because using edges is reccomended instead of the LINKS, LINKLIST,...
Hope it helps

OO Design of JavaBeans

I'm questioning the way that I have been designing my JavaBeans. For example, say I have the following:
Employee - basic employee information:
private String employee_id;
private String first_name;
private String last_name;
private String phone;
private String deptNo;
etc..
WorkflowPlayer - details about an employee in a system workflow:
private String workflow_instance_id;
private String employee_id;
private String role_class_id;
private String role_required;
private Employee employee;
private RoleClass roleClass;
RoleClass - details of a type of role (Approver, SecurityReviewer, Originator, Instructor, Manager, etc..)
private String role_class_id;
private String name;
private String label;
private String description;
These three models also correspond directly to Database tables (Employee is a read only view for me, if that matters)
Then in my view I would do something like
workflow_player.employee.first_name
workflow_player.roleClass.label
Is it acceptable to make Employee an instance variable? Or should I instead be extending WorkflowPlayer with Employee and then do
workflow_player.first_name
this makes sense for employee but not for roleClass.
workflow_player.description //NO!
I just want to use a consistent [correct] pattern
Yes, it's ok to make Employee an instance variable if you are referring to it from another table. Subclassing in this case is wrong because from your description it sounds like workflow is not a specialized kind of employee. Ask yourself if the lifecycles of these entities are the same or different, and if the subclass is substitutable for the superclass in all situations.
Subclassing should be a last resort reserved for cases where some entity is a specialized version of another entity and you want to refer to the specialized versions by their superclass.
There are specific patterns where subclassing is used in Object-relational mapping: table per class hierarchy, table per subclass, table per concrete entity, etc. The Hibernate documentation describes them. You would use inheritance in mapping objects to tables when your tables fall into one of those patterns. Even if you're not using Hibernate that's still a good example to follow.
I think role classes are a great design approach, and many developers do not use them. This matches the canonical use of role classes: when an entity participates in different activities, and within those activities, the view of that type is different. A good example would be the following. Suppose we were modeling payroll. We have a user who is both one of the employees who is getting paid, and an administrator in the app. In Java, we would have to model that as role classes because we don't have multiple inheritance, but it's really a more accurate representation because the role class, if it does confer any additional behavior or properties, it is doing so in the context of its own behavior. So for instance, whatever powers you need to grant the administrator in the payroll is confined to that realm.
It's also not an either/or situation: in the Payroll, you might want to show that some employees are also managers. That probably would best be done with inheritance, but the role class is still valid, again, as a way of representing participation.
You can't map JavaBean directly to Tables, because OO is not the same as Relational (Database).
You could use an ORM, like Hibernate, to map you JavaBean to SGBD Tables properly.
From an OO point of view, beans should be like that
public class Employee {
private String id;
private String firstName;
private String lastName;
private String phone;
private String deptNo;
}
public class WorkflowPlayer {
private String id;
private String roleRequired;
private Employee employee;
private Role roleClass;
}
public class RoleClass {
private String id;
private String name;
private String label;
private String description;
}

Categories