How do I setup CreatedAt and UpdatedAt in go-gorm join tables? - go-gorm

I am trying to setup audit timestamps for my GORM models.
How do I add UpdatedAt and CreatedAt timestamp fields for the many2many tables? For example, if I have a model like this, how do I set timestamps for customer_roles table?
type Customer struct {
ID string `gorm:"primaryKey"`
Email string `gorm:"unique"`
CreatedAt time.Time
UpdatedAt time.Time
Roles []Role `gorm:"many2many:customer_roles;"`
}
Thanks for your help!

Related

Cascading delete with sqlite isn't working with a join table

If you have a table that's just a hash of a many-to-many relationship between two other tables, like :
type User struct{
UserId string
...
}
type Roles struct{
Level string
...
}
where UserId and Level are PrimaryKeys.
The "join table" was originally:
type User_Role struct{
UserId string
Level string
}
How can you build that in gorm with cascading foreign key relataionships, et al.
I've been trying to piece it together from their docs, and different sources, but when I delete either the user or role, the join table still has the records.
Currently, this is what I've got:
type User_Roles struct {
User_Id string `gorm:"primaryKey; not null;ForeignKey:user_id;references:users.user_id,constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
Level string `gorm:"primaryKey; not null;ForeignKey:level;references:roles.level,constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
When I had fields in the struct for User and Role sqlite created the table with every field from both, doing it this way created the table with the right fields, but the cascading isn't working.
Foreign key checks are disabled in SQLite by default, you need to enable them:
db.Exec("PRAGMA foreign_keys = ON")
If you specify the foreign key relations like this, they should work as you'd expect:
type User struct {
UserId string `gorm:"primaryKey;not null;"`
UserRoles []User_Roles `gorm:"foreignKey:UserId;references:UserId;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}
type User_Roles struct {
UserId string `gorm:"primaryKey;not null;"`
Level string `gorm:"primaryKey;not null;"`
}
i.e. if you delete a user, its associations will be removed.

How can I adjust prisma scheme to 'autofil'

I just started using prisma and was wondering whether you could perform an 'autofill'.
For instance: I have a leaderboard, and whenever I list down the teamID, the teamName column gets filled up automatically.
A piece of the schema is as follows.
model LeagueTable {
id Int #id #default(autoincrement())
competitionId Int
teamId Int
played Int
won Int
drawn Int
lost Int
points Int
goalsFor Int
goalsAgainst Int
goalDifference Int
tname String
competition Competitions #relation("competition-lt", fields: [competitionId], references: [id])
team Teams #relation("team", fields: [teamId], references: [id])
}
model Teams {
id Int #id #default(autoincrement())
name String #unique
matchesAsAway Fixtures[] #relation("awayTeam")
matchesAsHome Fixtures[] #relation("homeTeam")
leagueTable LeagueTable[] #relation("team")
}
I was thinking of adding a relation but at the same time I am trying to normalise the scheme as a possible.
Prisma Studio Leaguetable Preview
As you can see the tName column is empty, and I would need to fill it up manually. Is there a way to have it filled up when inserting the teamID
The only way to accomplish this in Prisma is to add another relation as you mentioned.
It might be possible with custom SQL triggers (like before insert), but you would be well outside the Prisma happy path.

Prisma: Create or Connect Records in Explicit Many-to-Many Relations

In my Prisma Schema, I'm finding it difficult to undertand how to to create records in case of explicit many-to-many relations.
I have the following schema. Basically it represents Lists of Books. Users can Create Lists of Books.
A user can create a New list and then add books to this list along with their own notes. The Book Model is pure and contains standard book information.
The extra model is required because the user who is adding the book to the list can add his own notes about the book.
model List {
id Int #default(autoincrement()) #id
title String
slug String?
content String?
published Boolean #default(false)
author User? #relation(fields: [authorId], references: [id])
authorId Int?
books BooksInLists[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
model BooksInLists {
list List #relation(fields: [listId], references: [id])
listId Int // relation scalar field (used in the `#relation` attribute above)
book Book #relation(fields: [bookId], references: [id])
bookId Int // relation scalar field (used in the `#relation` attribute above)
##id([listId, bookId])
adder User? #relation(fields: [adderId], references: [id])
adderId Int?
notes String?
}
model Book {
id Int #id #default(autoincrement())
name String
lists BooksInLists[]
curator User? #relation(fields: [curatorId], references: [id])
curatorId Int?
bookDescription String?
}
model User {
id Int #default(autoincrement()) #id
name String?
email String? #unique
lists List[]
books Book[]
booksinlists BooksInLists[]
##map(name: "users")
}
The queries that I want to be able to do.
While updating a list, I should be able to add a new book to the list. This should create the new book, and also allow me to add a new record in BooksInLists model along with the 'notes' field.
While updating a list, I should be able to add/connect an existing book to the list. This will allow me to add a new record in BooksInLists model along with the 'notes' field.
It will be something like that:
prisma.booksInLists.create({
data: {
list: {
connect: {
id: 99
},
},
book: {
create: {
name: 'Young Lions'
}
}
}
})
However I see flaws in database schema. Model BooksInLists connects Books and List, so you don't need adder relation. In turn in Book model you shouldn't add curator relation because it's many to many relation. You have to use junction table usersBooks that connects User and Book tables.

SQL Server 2008R2 Indexes for log table

I have to do some logging in my app. Daily payload is about 50000 insertions. I have to store several fields, the most important - event type and event date/time. There gonna be queries with sorting, paging and filtering. What indexes (on what fields and clustered or non-clusterd) should I create in order to minify insertions and query time (at least for select .. where on the fields above)? Googling give various ideas on the subjuct so I can't figure out what to do
UPD
My POCO:
public class LogEntry
{
public DateTime LoggedAt { get; set; }
public int EventType { get; set; }
public bool IsSuccesful { get; set; }
public string Message { get; set; }
public string URL { get; set; }
public string Login { get; set; }
public string IP { get; set; }
public string UserAgent { get; set; }
}
The most frequent query is select .. where (LoggedAt between .. and ..) and (EventType=..). Sometimes there may be additional and parts of where clause.
Also no update operations are planned. Deletions are possible but only occasionally by lagre bulks.
Following statements is only for ilustrate some possible cases. Ofc its difficult to provide you a specific solution (you have to describe your selectivity). But you can see here some points of view and maybe it can help you.
Some rulles that can help you:
more indexes -> hardest insert
- do best index for majority of selectivity on as much as is possible unique value...
clustered index - replaces your heap by B-Tree
nonclustered index - referencing pages to your heap (creates new object) - consumes more space -> index + data
-- your table should seems like :
CREATE TABLE LogEntry (LoggedAt DATETIME,
EventType INT,
IsSuccesful BIT,
Message VARCHAR(511),--check your input to set it correctly
URL VARCHAR(511),--check your input to set it correctly
Login VARCHAR(127),--check your input to set it correctly
IP VARCHAR(63),--check your input to set it correctly
UserAgent VARCHAR(63))--check your input to set it correctly
-- For examlle for following select
SELECT *
FROM LogEntry
WHERE LoggedAt BETWEEN GETDATE() AND DATEADD(dd,-1,GETDATE()) AND
EventType = 1
-- can help following index (ofc unique values is best for clustered indexes)
CREATE CLUSTERED INDEX idx_LogEntry_LoggedAt_EventType ON dbo.LogEntry (LoggedAt,EventType)
-- For example for following select
SELECT Message
FROM LogEntry
WHERE LoggedAt BETWEEN GETDATE() AND DATEADD(dd,-1,GETDATE()) AND
EventType = 1
-- can help following index
CREATE NONCLUSTERED INDEX idx_LogEntry_LoggedAt_EventType ON dbo.LogEntry (LoggedAt,EventType) INCLUDE (Message)
-- and so ... it really depends what you really want...
-- for me can be really helpfull following solution:
CREATE TABLE LogEntryO (LogEntryId INT IDENTITY PRIMARY KEY CLUSTERED, -- my clustered index
LoggedAt DATETIME,
EventType INT,
IsSuccesful BIT,
Message VARCHAR(511),--check your input to set it correctly
URL VARCHAR(511),--check your input to set it correctly
Login VARCHAR(127),--check your input to set it correctly
IP VARCHAR(63),--check your input to set it correctly
UserAgent VARCHAR(63))--check your input to set it correctly
-- + following index
CREATE NONCLUSTERED INDEX idx_LogEntryO_LoggedAt_EventType ON dbo.LogEntryO (LoggedAt) INCLUDE (LogEntryId)
-- and my query should seems
;WITH CTE AS (SELECT LogEntryId FROM dbo.LogEntryO WHERE LoggedAt BETWEEN GETDATE() AND DATEADD(dd,-1,GETDATE()))
SELECT *
FROM dbo.LogEntryO a
JOIN CTE b ON a.LogEntryId = b.LogEntryId
WHERE a.EventType = 1
It is really hard to create best solution for you, because it seems that you using c# class for accesing to this table. For example you could using some kind of ORM , for example entity framework or soo...
It's difficult to give a specific answers without more information. Any way, I think you can try using an index with your two most important field.
Remember (but may be you already know it) the order of the field is important with respect the query you do.
If you know that the query is always the same, you can add others filed (in the index or with INCLUDE column).
Evaluate the "cardinality" of the fields value too.
If possible, give often a look at the information MSSQL stores about the use of the index.
If it is a OLTP system, with frequent update/delete, it could be not positive to add too much indexes.

What should I make the type of a "marital status" field?

I have a field in my table "marital status" , the user has to choose (radiobutton) if he's (married, divorced, single, voeuf)
What should I make the type of this field?
Is there a boolean type?
marital status doesn't sound like a boolean anyway. It sounds like an enumeration. A boolean would be married (Y/N), although I think in this day and age you might want to be able to store multiple kinds of relationships in there, and you specified yourself that you need to store 'devorced' as well, so a boolean is out of the question.
So I'd recommend making a table named MaritalStatus, having an ID and a description. Store the various states in there, and make a foreign key to MaritalStatusID in your table.
Make it an INT field , Create another table in your database something like
CREATE TABLE dbo.MaritalStatus
(
M_ID INT PRIMARY KEY NOT NULL,
M_Status NVARCHAR(20)
)
GO
INSERT INTO dbo.MaritalStatus
VALUES
(1, 'Single'),(2,'Married'),(3,'Divorced'),
(4,'Widowed'),(5,'Other'),(6,'Prefer Not to say').... bla bla
Now in your Table in "Marital Status" field refer to a user Marital Status using INT values from dbo.MaritalStatus table's "M_ID".
Boolean or in SQL bit datatype is best when you have a situation where something can be TRUE or NOT TRUE, for someone's Marital Status there can be more than two possible values therefore you should create a separate table for all the possible Marital Status and use Foreign key constraint.
The boolean equivalent for T-SQL is bit.
Though, it seems like you want more than a yes/no answer. In this case use an int and then convert the int to an enum.
Edit: Dukeling removed the C# tag in an edit, so I am not sure how relevant this part is anymore /Edit
The enum:
enum MaritalStatus
{
Single,
Married,
Divorced,
...
}
The int from DB:
int maritalStatusFromDB = //value from DB
Convert int to enum:
MaritalStatus maritalStatus = (MaritalStatus)maritalStatusFromDB;
Be aware that your database may contain int values that are not defined in your enum, such as 10. You can check whether maritalStatusFromDB is a valid MaritalStatus as follows:
bool isValid = Enum.IsDefined(typeof(MaritalStatus), maritalStatusFromDB);
if( isValid == false )
{
//handle appropriately
}