Implicit or Explicit Many to Many relationship in prisma - database

When should you use a implicit many to many relationship in prisma and when explicit many to many relationship ?
Do they have any trade-off or anything that should be noted

Short answer: Prefer the implicit relationship unless you need to store additional meta-information about the relation itself.
For example, a plain n-m relation between Post and Category would look like this in the implicit version:
model Post {
id Int #id #default(autoincrement())
title String
categories Category[]
}
model Category {
id Int #id #default(autoincrement())
name String
posts Post[]
}
Now, if you need to store meta-data about this relation, e.g. information when an Post has been added to a Category, you should create an explicit version:
model Post {
id Int #id #default(autoincrement())
title String
categories CategoriesOnPosts[]
}
model Category {
id Int #id #default(autoincrement())
name String
posts CategoriesOnPosts[]
}
model CategoriesOnPosts {
post Post #relation(fields: [postId], references: [id])
postId Int
category Category #relation(fields: [categoryId], references: [id])
categoryId Int
assignedAt DateTime #default(now())
##id([postId, categoryId])
}
The main tradeoff really is convenience. It's much simpler to work with an implicit relationship because the relation table is maintained for you under the hood. Also, the relation queries in the Prisma Client API are easier to work with because you save "one hop" in the connect API (with an explicit relation table, you always have to "go through" the relation table in your Prisma Client queries).
Also, you can migrate an implicit relation to an explicit relation later down the line. So you can always start with an implicit one and turn it into an explicit relation later when needed.

Related

How to handle linked models?

I have two models, using Go 1.19:
type User struct {
Name string
ID int
}
type Order struct {
ID int
Name string
User *User
// or
UserID int
}
Of course, the database orders table has a foreign key to the users table via user_id.
Probably in different situations I have to use one of these models. When exactly?
Mb only user_id in DTO models, the user in responses from the server?
I will be glad for any information :)
It depends on your purpose. As usual, you have to use id when a table to include has meta info about your entity (often it's tables with a lot of rows and so heavy), therefore it will be better to use id, otherwise if it's table which describe some fields in initial table, you can use full entity.

GAE datastore foreign key and join

i'm struggling with gae for something that looks very simple to me.
let me explain.
i have a table with data about a person, i decided to use email as id
#Entity
public class Person{
#Id
#Column(name = "email")
String email;
...
what i would like to accomplish is
create a table with two columns, both containing email from Person, with the meaning "email in column 1 has written to email in column 2"
when i delete a row from Person, i would like that all the rows in the table at point 1 that contain this Person email in column 1 or 2 would be deleted as a cascade effect
i want to query my database so that, given an email address, i will be able to join all the rows in the table at point 1 and extract all the datas (name, phone...) of the Persons the given email has written to.
trouble is that apparently in gae i cannot use join, and i simply can't understand how to create a join table with cascade effect.
any help is welcome.
thanks in advance
Datastore isn't a relational database, so you should familiarise yourself with the concepts before starting to design a solution. What you're trying to do is fit a square peg into a round hole: not only will you find you're missing joins, you will also have to implement your own cascade-on-delete (hint: you may not want to do this but if you did, and you have a lot of data, look at Task Queues).
You don't provide much in the way of code, and I don't know JPA (tip: look at Objectify, it's much more suitable for the non-relational Datastore) but you might want something like this (using Objectify annotations):
#Entity
public class Person {
#Id
String email;
...
}
Then I'm assuming you will have some kind of Message entity (what you refer to as a two-column table):
#Entity
public class Message {
#Id
Long msgId;
#Index
Ref<Person> from;
#Index
Ref<Person> to;
...
}
Depending on what queries you need to perform, you may need to create a custom index (read here). Remember, queries on Datastore are index scans.
But, say, you want to get messages sent from Person A to Person B, you can do something like:
Person a = ofy().load().type(Person.class).id("a#example.com").now();
Person b = ofy().load().type(Person.class).id("b#example.com").now();
...
ofy().load().type(Person.class).filter("from =", Ref.create(a)).filter("to =", Ref.create(b)).list();
Instead of using Ref<Person> (essentially a Key), you could of course use a String representing the email. You may also not want to use email as the #Id as that would prevent a user changing their email address.

Can I order by GeneratedValue Entity Ids to get the last added entity

On every request to my SessionBean I need to receive the last added instance of a JPA entity whose PK is declared with #Id #GeneratedValue(strategy=GenerationType.AUTO) Long id.
My current approach is to add ORDER BY e.id DESC to the query. Unfortunately im not sure whether generated ids are strictly increasing for subsequently persisted entities and I can't seem to find any documentation on that topic. Can anyone help me with that?
JPA does not specify the order of id generation, so the provider is free to issue nonsequential ids.
If you want to rely on the entity insertion order, consider adding a temporal createdAt or modifiedAt field to your entity. This approach is used by some persistace frameworks, e.g. ActiveRecord.
You can leave the generation of this value to the provider by using a callback in a base entity class:
#PrePersist
void makeCreationTimestamp() {
createdAt = System.currentTimeMillis();
}

Inheritance and model Id

I have a Person class in Contacts subsystem. On the other hand in CRM subsystem, I have the notion of Customer.
In database design, I want to create a relationship between these notions. There are some possible ways:
Each customer is a person, thus customer should inherit from person and customer dies as soon as his person is removed (Composition). In this case, we create a one-to-one relationship between Id columns of the Customers table and People table, and we make the Id column of the People table an identity field, but we explicitly insert the scope_identity() in the Customers table.
Each customer has a person, thus customer and person have their own life-cycles (Aggregation) and can survive without the other. In this scenario, Customers table should have a foreign key to People table. The bad point here is that each Person can have many Customers which seems odd to me.
Which design is suggested as the best practice? I need solid objective answers. Thank you.
There are different cases when you may or may not give each table it's own ID.
In your case, it would be better if customer table does have it's own ID.
Example:
Own Id in a many to many relation defining table is redundant, when it doesn't have any extra column associated apart from the tables it is joining. Consider a Teacher and Student table relation. They have a many to many relation. If there is a table named TeacherStudentRelation having only foreign key to Teacher and Student table then it won't need any extra OwnId field.
But in your case, a Customer table surely would have extra information associated like balance, purchaseList or anything like that. And it is highly likely that you would search into Customer table for some data. Here an OwnId of customer table would let you to index that table.
Briefly, do give Customer table it's own Id.
IHMO, every entity must have a proper ID. You write about foreign key to refer Person as Customer, but this is another concept.
If Person is a base class about Customer, so, the ID field is the same and you don't explicit in Customer class because it inherit by Person.
In the first case (Person and Customer with FK) you have:
class Person {
private String id;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
class Customer {
private String id; // this is different by id of Person class
private Person person;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
In the second case (Customer extends Person) you have:
class Person {
private String id;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
class Customer extends Person {
... other properties about Customer
... put here get and set property
}

How to design database request/approval tables?

I have the following kind of request tables:
oversea_study_request
course_request
leave_request
in these request functions, approving officer can post multiple remarks and also approve or reject the request. The system must be able to capture the history of the actions taken.
What is the best way to design it?
Should I create a common table to store the approval information and remarks.
Should I store in each request table the approval information and remarks instead.
Can someone advise on the pros and cons of each approach?
Similar to the fields organisation question here: How to better organise database to account for changing status in users; and my answer there:
If the all the requests have the same fields, field types and info, including mandatory (NOT NULL) and optional, etc. then it's better to put all the requests into one requests table. Designate one field to be request_type, with an int for efficiency and SQL convenience, or an ENUM type. Example:
overseas study = 1
course = 2
leave = 3
Similarly, do that for the approvals table also...if the process is the same for each type then store those together. Store the request id (requests.id). Since you have multiple approval-comments and approval+rejection possible, store these in approvals.action and approvals.action_date. If "actions" are independent of "approve/reject" - that is, if you can post a comment without approving/rejecting OR if you can approve/reject without a comment - then store the actions and comments separately, and include the request.id.
So you have:
Table1: requests
id INT
request_type INT (or ENUM)
request_date DATETIME
...
Table2: approvals (or 'actions', to be general)
id
request_id # (refers to requests.id above)
action_type # (approve or reject)
action_date
comment
If comments and approvals are NOT necessarily together, then:
Table2: actions
id, request_id, action_type, action_date
Table3: comments
id, request_id, comment, comment_date
And of course, add the user_id, username, etc. tables/fields. (The id in each table is it's own Primary Key)
Each request + actions + comments can be found with a SELECT and LEFT JOINs
Btw, it's "overseas" study, not "oversea" study - it's not a course in an airplane ;-)

Resources