Grails doesn't create foreign key column in PostgreSQL - postgresql

I am having trouble generating my tables in PostgreSQL from Grails. I have simple Email and EmailAttachment domain classes with a hasMany and belongsTo relationship. This setup worked well on our production server (AS400 DB2), but when I try to run my program on PostgreSQL (the new dev environment), the Email class does not have the attachment_id column.
Email.groovy:
class Email {
static hasMany = [attachments:EmailAttachment]
Integer id
Integer version = 0
String subject
String recipients
String sender
Date sentDate
String plainTextMessage
Set attachments
static mapping = {
datasources(['DEFAULT'])
table name:'error_email', schema: Appointment.schema
sort sentDate:'desc'
}
static constraints = {
subject nullable:true
version nullable:true
recipients nullable:true
sender nullable:true
sentDate nullable:true
plainTextMessage nullable:true
attachments nullable:true
}
def String toString(){
return subject
}
}
EmailAttachment.groovy:
class EmailAttachment {
static belongsTo = [email:ErrorEmail]
ErrorEmail email
String filename
byte[] content
static mapping = {
datasources(['DEFAULT'])
table name:'error_email_attachment', schema: Appointment.schema
}
static constraints = {
filename nullable:true
content nullable:true
}
}
Also, here are the relevant lines from schema-export:
alter table program.email_attachment drop constraint FK2E592AFD1D80E229;
drop table program.email cascade;
drop table program.email_attachment cascade;
drop sequence hibernate_sequence;
create table program.email (id int4 not null, version int4, plain_text_message varchar(255), recipients varchar(255), sender varchar(255), sent_date timestamp, subject varchar(255), primary key (id));
create table program.email_attachment (id int8 not null, version int8 not null, content bytea, email_id int4 not null, filename varchar(255), primary key (id));
alter table program.email_attachment add constraint FK2E592AFD1D80E229 foreign key (email_id) references program.error_email;
create sequence hibernate_sequence;
I've tried specifying joinTable: attachments joinTable:[name: 'email_table', column: 'attachment_id', key: 'id'] to no avail, as well as leaving it out, and trying other collection types for attachment. Thanks in advance for your time and brain cells.

The email doesn't have an attachment_id column because it's the one side of the one-to-many. The many side, attachment in this case, has a reference to its owning email in the email_id int4 not null column. Given an email with id 42 you (and Grails/GORM/Hibernate) can find all of the attachments by querying for all rows in that table with email_id=42.

Related

Diesel migration force String instead of Uuid in schema.rs

I have a problem with the diesel migration. I need to implement Uuid as primary key for a model. I got a lot of issues with the Uuid integration (feature uuidv07, uuid crate,..) but when I specify the type uuid in the migration, diesel generate a "Varchar" field in the migration, so I can't use Uuid as a type of field in my model.
users.sql
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR NOT NULL,
name VARCHAR NOT NULL,
password VARCHAR NOT NULL,
id_role INT,
CONSTRAINT fk_role
FOREIGN KEY(id_role)
REFERENCES roles(id)
)
schema.rs
table! {
users (id) {
id -> Varchar,
email -> Varchar,
name -> Varchar,
password -> Varchar,
id_role -> Nullable<Int4>,
}
}
Is this normal to use Varchar and not Uuid ?
uuid = { version = "0.8.2", features = ["serde", "v4"] }
diesel = { version = "1.4.5", features = ["postgres", "r2d2", "uuidv07"] }
Thanks.
Diesel does not force anything onto you. It just reads the types from your database system. So if it outputs a Varchar as type for a specific column that means your database system recorded Varchar (for whatever reason) as type for this column. Or to word it differently: The problem here is not diesel, but likely an interaction between your migration, your existing database schema and your database. As neither information about your pre-existing database schema nor about your database system is provided as part of your question there is not much I can add here to point you into the right direction.

Include columns from related table in JPA using ListAll()

I have 2 related tables and i am wondering if it is possible to include other columns (like firstname and surname) from table no1 when i am calling the function ListAll() in table no2? I am using JPA with Session Beans (AbstractFacade) and JSF Pages. Thanks in advance :-)
Table No1
CREATE TABLE cases (
caseid INT AUTO_INCREMENT PRIMARY KEY,
category VARCHAR(32),
descript VARCHAR(512),
isDone TINYINT,
userid INT,
INDEX user_ind(userid),
FOREIGN KEY (userid) REFERENCES USERS(userid)
);
Table 2
CREATE TABLE users (
userid INT NOT NULL AUTO_INCREMENT,
firstname VARCHAR(64) NOT NULL,
surname VARCHAR(64) NOT NULL,
telephone VARCHAR(12),
email VARCHAR(64),
PRIMARY KEY (userid)
);
Entity Controller
#Named(value = "caseController")
#SessionScoped
public class CaseController implements Serializable {
#EJB
CasesFacade casesFacade;
#Inject
CasesBean casesBean;
public List<Cases> getAll() {
return casesFacade.findAll();
}
If i correct understand maybe the good idea will be unpack chosen columns/fields to custom DTO on level repository or in code.

Prisma2 prisma introspect returning weird values for foreign keys

I have two tables, User and Relationship. The tables are used to store a parent child relationship. I am using Postgres
// schema.sql
CREATE TABLE "public"."Relationships" (
id SERIAL PRIMARY KEY NOT NULL,
parent_id INT NOT NULL,
FOREIGN KEY (parent_id) REFERENCES "User" (id),
child_id INT NOT NULL,
FOREIGN KEY (child_id) REFERENCES "User" (id)
)
CREATE TABLE "public"."User" (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(128) NOT NULL,
email VARCHAR(128) UNIQUE,
password VARCHAR(128) NOT NULL,
isChild BOOLEAN NOT NULL DEFAULT false
created_at TIMESTAMP NOT NULL DEFAULT NOW();
);
When I run npx prisma introspect the following is returned in the schema.prisma file.
// schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Relationships {
child_id Int
id Int #default(autoincrement()) #id
parent_id Int
User_Relationships_child_idToUser User #relation("Relationships_child_idToUser", fields: [child_id], references: [id])
User_Relationships_parent_idToUser User #relation("Relationships_parent_idToUser", fields: [parent_id], references: [id])
}
model User {
created_at DateTime #default(now())
email String? #unique
id Int #default(autoincrement()) #id
ischild Boolean #default(false)
name String?
password String
Relationships_Relationships_child_idToUser Relationships[] #relation("Relationships_child_idToUser")
Relationships_Relationships_parent_idToUser Relationships[] #relation("Relationships_parent_idToUser")
}
I dont understand what User_Relationships_child_idToUser and User_Relationships_parent_idToUser are and why they are not just the simple syntax that appears for foreign keys in the Prisma docs tutorial.
Prisma's introspection generates two fields for each foreign key:
the relation scalar field (basically the direct representation of the foreign key)
a relation field (annotated with the #relation attribute) – these are the fields that seem to confuse you. The reason they provide is such that you can work with the relations easily in the Prisma Client API.
You can find more info about this in the docs here.
Of course User_Relationships_parent_idToUser and User_Relationships_child_idToUser are not very nice names. You can manually adjust the schema after introspection and rename the relation fields to have friendlier names, e.g:
model Relationships {
child_id Int
id Int #default(autoincrement()) #id
parent_id Int
child User #relation("Relationships_child_idToUser", fields: [child_id], references: [id])
parent User #relation("Relationships_parent_idToUser", fields: [parent_id], references: [id])
}

Struggling to manually create relations with gorm / migrate

I have an sql structure like so:
CREATE TABLE resources (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
deleted_at TIMESTAMPTZ
);
CREATE TABLE tags (
name TEXT PRIMARY KEY
);
What sql do I need to write, how can I tell gorm that I want a Resource to have many Tags? This is what I have currently go-wise:
package models
import (
"github.com/jinzhu/gorm"
)
type Tag struct {
Name string `gorm:"PRIMARY_KEY"`
}
type Resource struct {
gorm.Model
Title string
Tags []Tag `gorm:""`
}
Note that I explicitly do not want to auto-migrate via gorm. I am using the migrate tool to handle migrations and want to specifically handle them manually, not with go.
To define a has many relationship, a foreign key must exist.
So for your case Tag should be:
type Tag struct {
gorm.Model
Name string `gorm:"PRIMARY_KEY"`
ResourceID int
}
and Resource:
type Resource struct {
gorm.Model
Title string
Tags []Tag `gorm:"foreignkey:ResourceID"`
}
And your sql structure should have that foreign key ResourceID column.
Not sure if you have already checked this but it contains more details in case you need them: https://gorm.io/docs/has_many.html#Foreign-Key

"Can't adapt type" error on a Foreign key attribute with SQLAlchemy/PostGreSQL

I got a problem with PostGreSQL 8.4 and tables reflection. My metadata object seems to be ok (it has foreign keys, primary keys, every columns and tables). But when I try to associate an object to an another one through a Foreign key, I get : "sqlalchemy.exc.ProgrammingError: (ProgrammingError) can't adapt type 'EventParameters' 'INSERT INTO event (".
I'm using SQLAlchemy 0.6.3 (psycopg2 2.2.1) and PostGreSQL 8.4.5
Here, my code :
#! /usr/bin/env python
from sqlalchemy import MetaData, create_engine
from sqlalchemy.orm import mapper, sessionmaker
class EventParameters(object):
pass
class Event(object):
pass
engine = create_engine('postgresql://postgres:toto#127.0.0.1:5432/renass')
metadata = MetaData()
metadata.reflect(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()
mapper(EventParameters, metadata.tables['eventparameters'])
mapper(Event, metadata.tables['event'])
ep = EventParameters()
ep.publicid = 'test'
e = Event()
e.publicid = 'test'
e.eventparametersid=ep
session.add(e)
session.commit()
and my database :
CREATE TABLE EventParameters (
id SERIAL PRIMARY KEY,
publicID varchar(255) UNIQUE NOT NULL,
description varchar(255),
creationInfo_agencyID varchar(64),
creationInfo_agencyURI varchar(255),
creationInfo_author varchar(128),
creationInfo_authorURI varchar(255),
creationInfo_creationTime time,
creationInfo_version varchar(64)
);
CREATE TABLE Event (
id SERIAL PRIMARY KEY,
eventParametersID integer NOT NULL REFERENCES EventParameters(id),
publicID varchar(255) UNIQUE NOT NULL,
preferredOriginID integer,
preferredMagnitudeID integer,
preferredFocalMechanismID integer,
type EventType,
typeCertainty EventTypeCertainty,
creationInfo_agencyID varchar(64),
creationInfo_agencyURI varchar(255),
creationInfo_author varchar(128),
creationInfo_authorURI varchar(255),
creationInfo_creationTime time,
creationInfo_version varchar(64)
);
It seems that SQLAlchemy don't recognize the attribute "eventparametersid" as a relationship ...
Thank you in advance
Fabien
To make your code working you should change the mapper invocation for the Event class to include the mapping between the two classes
mapper(Event, metadata.tables['event'], properties={
'eventparameters': relation(EventParameters)
})
then use that column to assign the EventParameters instance
ep = EventParameters()
ep.publicid = 'test'
e = Event()
e.publicid = 'test'
e.eventparameters = ep