difference between collection and association mapping in mybatis 3 - mysql

I am doing mysql queries execution from mybatis3.
I am new to this.
What is the difference between collection and association mapping in mybatis 3?
Specific example below.
SELECT e.empid AS empid,e.empname AS empname,
e.empsalary AS empsalary,p.proname AS proname,p.proid AS proid
FROM projects p,employees e,projectassigns pa
WHERE pa.empid=e.empid AND pa.proid=p.proid;
I need all the details of employee and project.
I have given the result map as follows.
<resultMap id="resultProjects" type="com.pratap.model.ProjAssigns">
<association property="employee" javaType="com.pratap.model.Employee"
resultMap="resultEmployees" />
<association property="project" javaType="com.pratap.model.Project"
resultMap="resultProjects" />
</resultMap>
Can anybody explain the difference taking my example or your own example?
I am confused with this..
Thank you.

I am going to assume that you have a many to many relationship between Projects and Employees, which is why you created a Project Assignment table. This Project Assignment table / object may only have two fields/columns: a mapping of project id to employee id - a classic "bridge table" (aka "join" or "junction" table).
When you map this model to an object graph, you have three options:
A Project object can have a list of all employees assigned to it
An Employee object can have a list of projects s/he is assigned to
Create a Project Assignment object that has a mapping of each projects to its employee and each employee to his/her project.
In your example you chose the last option.
Association
An association is a single mapping for a "has-one" relationship.
Suppose an Employee can only be assigned to one Project at a time. Some models call this a "has-one" or "belongs to" relationship. If you want to make Employee your "primary" focus in the object graph, then you would map it with an association to his/her Project:
<resultMap id="employeeResultMap" type="Employee">
<constructor>
<idArg column="employee_id" javaType="_integer"/>
</constructor>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
<!-- etc. for other simple properties of Employee -->
<!-- Project is a "complex property" of Employee, so we use an -->
<!-- association to grab all of the Projects properties also -->
<association property="assignedProject" resultMap="projectResultMap"/>
</resultMap>
In this case your objects would look like this:
public Employee {
int id;
String firstName;
String lastName
Project assignedProject;
}
public Project {
int id;
String name;
String abc;
}
Collection
An collection is a "list" or "set" of associations.
Now model the inverse - we make Project the primary focus. A Project has a "has-many" relationship with Employee, so it will have a list or collection of those, so we use a "collection" mapping:
<resultMap id="projectResultMap" type="Project">
<constructor>
<idArg column="project_id" javaType="_integer"/>
<arg column="name" javaType="String"/>
</constructor>
<result property="abc" column="abc"/>
<!-- This tells mybatis that there can be multiple Employees -->
<!-- to look up and get their properties -->
<collection property="employees" ofType="Employee">
<constructor>
<idArg column="employee_id" javaType="_integer"/>
</constructor>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
</collection>
</resultMap>
Now your objects would look like this:
public Employee {
int id;
String firstName;
String lastName
}
public Project {
int id;
String name;
String abc;
List<Employee> employees;
}
Project Association
To have a Project Association object, you would either need:
A single Project Association object that maps all projects to employees and vice versa
One Project Association object per project, mapping a project to its employees
One Project Association object per employee, mapping an employee to his/her projects
The first option is rather complex and messy - you would be trying to do relational mapping with object graphs (hash tables most likely).
I would choose to make one of the entities (Project or Employee) the primary focus and then model it as I showed above. The one case I didn't cover is if Employee is your primary focus and an Employee can be on multiple projects, then make that a "has-many" relationship using a collection rather than the association I used above.
Final Note: if it would help to see examples of using a "has-one" association and a "has-many" collection, see the MyBatis Koans I created: https://github.com/midpeter444/mybatis-koans. Koans 10 and 11 demonstrate this.

Related

Changing attributes over time in relational database

At the core of my app is a table called Entities:
Entities:
-----------
id: number // PK
name: string
position_x: number
position_y: number
These entities have interactions with each other, called Events:
Events:
-----------
id: number // PK
name: string
date: Date
from: number // Entities FK
to: number // Entities FK
With events, we can manage all kinds of events between two entities. By selecting a timestamp / event, we can "time-travel" through each event, and see how changes affect the entities.
I just learned we want to support changes to entity attributes in the timeline as well. (travelling back should still get you the original attributes). So now I want to create a new Event-like table, which would look something like this:
SingleEntityEvents:
-----------
id: number // PK
name: string
date: Date
to: number // Entities FK
type: enum // CHANGE_NAME | CHANGE_POSITION
payload: json
Now my app would get the entities and render the original name if applicable, but render an updated name if there is a CHANGE_NAME event happening before the currently selected date. However, now I am leaning towards getting rid of the Entities table entirely, and make everything (including Entity creation) an event. But then how do I properly refer to these entities in the original (from -> to) Events? Is this even possible?
In other words, I want to be able to model this stream of events, but I am not sure how to:
Create entity through event:
name: 'Create Entity'
date: 01/01/2022
entityID: 123 // Its not to reference but to create an entity with this ID?
type: CREATE_ENTITY
payload: {
"name": "New Entity",
"position_x": 1,
"position_y": 0
}
If I select any time after this first event, the app should render an entity called "New Entity", positioned on coordinate (1, 0).
Update name of entity through event
name: 'Update Entity Name'
date: 01/03/2022
entityID: 123 // Now, since this is an update event, this is an actual reference to the previously created entity
type: UPDATE_ENTITY_NAME
payload: "Foo Bar"
If I select any time after this second event, the app should now render the same entity but it's now called "Foo Bar". Its position is unchanged so its still on (1, 0).
My question is, are there best practices to model such event streams? And how do I go about creating this entity ID?

writing script in scala to join two mysql tables and create one object (quill)

I have two mysql tables: Owners & Pets
Owner case class:
Owner(id: Int, name: String, age: Int)
Pet case class:
Pet(id: Int, ownerId: Int, type: String, name: String)
I want to create out of those tables list of OwnerAndPets:
case class OwnerAndPets(ownerId: Int,
name: String,
age: String,
pets: List[Pet])
(its for migrations purposes, I want to move those tables to be a collection of mongodb, which the collection documents would be OwnerAndPets objects)
I have two issues:
when I use join with quill on Owner & Pet I get list of tuples [(Owner, Pet)]
and if I have few pets for an owner I will get:
[(Owner(1, "john", 30), Pet(3,1,"dog","max")),
(Owner(1, "john", 30), Pet(4,1,"cat","snow"))]
I need it as (Owner(1, "john", 30), [Pet(3,1,"dog","max"), Pet(4,1,"cat","snow")])
how can I make it like this?
when I use join with quill on Owner & Pet I will not get owners that dont have pets and its fine cause this is what it supposed to be, but in my script in this case I would want to create object like:
OwnerAndPets(Owner(2, "mark", 30), List[])
Would appreciate any help, thanks
this is my join query:
query[Owner].join(query[Pet]).on((o, p) => o.id == p.o_id)
Your question highlights one of the major differences between FRM (Functional Relational Mapping) systems like Quill and Slick as opposed to ORMs like Hibernate. The purpose of FRM systems is not to build a particular domain-specific object hierarchy e.g. OwnersAndPets, but rather, to be able translate a single database query into some set of objects that can reasonably be pulled out of that single query's result set - this is typically a tuple. This means it is up to you to join the tuples (Owner_N, Pet_1-N) object into a single OwnersAndPets object in memory. Typically this can be done via groupBy and map operators:
run(query[Owner].join(query[Pet]).on((o, p) => o.id == p.o_id))
.groupBy(_._1)
.map({case (owner,ownerPetList) =>
OwnerAndPets(
owner.id,owner.name,owner.age+"", // Not sure why you made 'age' a String in OwnerAndPets
ownerPetList.map(_._2))
})
That said, there are some database vendors (e.g. Postgres) that internally implement array types so in some cases you can do the join on the database-level but this is not the case for MySQL and many others.

how can i update MVC models's particular field in tables using json array

String expenseIds = resourceRequest.getParameter("expenseIds");
JSONArray expenseArray = JSONFactoryUtil.createJSONArray(expenseIds);
LOG.info("JSON ARRAY" + expenseArray);
if (Validator.isNotNull(expenseIds)) {
for (int i = 0; i < expenseArray.length(); i++) {
LOG.info("Expense Id"+expenseArray.getInt(i));
}
This is my code and i am able to get expenseIds. and I want to update particular field using arrays id
Liferay ORM
Liferay uses ORM which means that you define your objects in service.xml and as part of the build process Liferay creates the objects, the persistence layer, and a utility method for accessing that persistence layer.
Assuming you have an expense object, defined below
<service-builder package-path="com.latham.request">
<entity name="Expense" local-service="true" remote-service="true">
<column name="expenseId" type="long" primary="true" />
</entity>
</service-builder>
To update that you would essentially do something like the following
Expense e = ExpenseLocalServiceUtil.getExpense(id);
e.setWhateverAttribute("helloWhateverAttribute");
ExpenseLocalServiceUtil.updateExpense(e);

Avoiding two distinct domain models with Spring Boot and Jackson

I'm designing a Spring Boot REST API that will be backed by MySQL. It has occurred to me that I want, effectively, two separate models for all my domain objects:
Model 1: Used between the outside world (REST clients) and my Spring REST controllers; and
Model 2: The entities used internally between by Spring Boot app and the MySQL database
For instance I might have a contacts table for holding personal/contact info:
CREATE TABLE contacts (
contact_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
contact_ref_id VARCHAR(36) NOT NULL,
contact_first_name VARCHAR(100) NOT NULL,
...many more fields
);
and the respective Spring/JPA/Hibernate entity for it might look like:
// Groovy pseudo-code!
#Entity
class Contact {
#Id
#Column(name = "contact_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
#Column(name = "contact_ref_id")
UUID refId
#Column(name = "contact_first_name")
String firstName
// ...etc.
}
If I only had a single model paradigm, then when Jackson goes to serialize a Contact instance (perhaps fetched back from the DB) into JSON and send it back to the client, they'd see JSON that looks like:
{
"id" : 45,
"refId" : "067e6162-3b6f-4ae2-a171-2470b63dff00",
"firstName" : "smeeb",
...
}
Nothing like exposing primary keys to the outside world! Instead, I'd like the serialized JSON to omit the id field (as well as others). Another example might be a lookup/reference table like Colors:
# Perhaps has 7 different color records for ROYGBIV
CREATE TABLE colors (
color_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
color_name VARCHAR(20) NOT NULL,
color_label VARCHAR(20) NOT NULL,
color_hexcode VARCHAR(20) NOT NULL,
# other stuff here
);
If the corresponding Color entity looked like this:
#Entity
class Color {
#Id
#Column(name = "color_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
#Column(name = "color_name")
String name
#Column(name = "color_label")
String label
#Column(name = "color_hexcode")
String hexcode
// ...etc.
}
Then with only one model it would serialize into JSON like so:
{
"id" : 958,
"name" : "Red",
"label" : "RED",
"hexcode" : "ff0000"
}
But maybe I just want it to come back as a simple string value:
{
"color" : "RED"
}
So it seems to me that I either need two separate models (and mapper classes that map between them) or I need a way to annotate my entities or configure either Spring, Jackson or maybe even Hibernate to apply certain transformations on my entities at the right time. Do these frameworks offer anything that can help me here, or am I going to have to go with two distinct domain models here?
You can actually accomplish this with just one model and I think it is the easiest way if you are just looking for hiding fields, custom formatting, simple transformation of attributes etc. Having two models require transformation from one model to another and vice-versa which is a pain. Jackson provides a lot of useful annotations which can be used to customize the output. Some of the annotations that can be useful for you are listed below
#JsonIgnore - ignore a field/attribute. You can hide your id field using this annotation.
#JsonInclude - Can be used to specify when a field should be present in output. For eg: Whether a field should be present in output if it is null
#JsonSerialize - You can specify a custom serializer for an attribute. For eg: You have an attribute 'password' and you want to output password as '****'.
#JsonFormat - You can apply a custom format to a field. This is very useful if you have date/time fields
#JsonProperty - If you want to give a different name for your field in your output. For eg: You have a field 'name' in your model and you want to display it as 'userName' in the output.

How does sqlmetal generate association names?

The association names sqlmetal generates have been the source of much frustration. Sometimes the association is simply the column name with "Id" taken off the end, sometimes it generates an association name based on the foreign key constraint name.
I simply cannot figure out what steps it uses to generate these names, and a recent schema change has drastically altered the association names once again, so I'd like to get a handle on this.
I have two tables which reference each other in a sort of chain. Something like this:
class In
{
int Id;
EntityRef<Out> Yields; // YieldsId => FK_Out_Source
EntitySet<Out> In_Source; // FK_In_Source
}
class Out
{
int Id;
EntityRef<In> Yields; // YieldsId => FK_In_Source
EntitySet<In> Out_Source; // FK_Out_Source
}
These were the classes prior to the schema change, where there was an extra FK field between In and Out tables. After deleting that field, sqlmetal now generates this:
class In
{
int Id;
EntityRef<Out> Yields; // YieldsId => FK_Out_Source
EntitySet<Out> Out; // FK_In_Source
}
class Out
{
int Id;
EntityRef<In> In; // YieldsId => FK_In_Source
EntitySet<In> Out_Source; // FK_Out_Source
}
The previous classes were perfectly symmetrical as they should be, but now the generated classes are completely asymmetrical. Can anyone explain this?
Since there seems to be no rhyme or reason to this, I created a command line tool that wraps sqlmetal and rewrites the association names. It's included in my open source Sasa utilities framework, and is called sasametal.