I want to express the following tables in GORM:
CREATE TABLE indexes (
id INTEGER PRIMARY KEY,
name VARCHAR
)
CREATE TABLE services (
id INTEGER PRIMARY KEY,
name VARCHAR
)
CREATE TABLE index_service (
index_id INTEGER REFERENCES indexes(id),
service_id INTEGER REFERENCES services(id),
write_active INTEGER,
PRIMARY KEY (index_id, service_id)
)
After reading through documentations and questions on stack overflow. I still cannot find an answer on how to express the additional column write_active in GORM's DSL
What I got so far is
type Index struct {
ID unit `json:"id" gorm:"primary_key"`
Name string `json:"name" gorm:"not null"`
}
type Service struct {
ID unit `json:"id" gorm:"primary_key"`
Name string `json:"name" gorm:"not null"`
}
However, I do not know how to write the composite table.
you need to create extra model like this:
package database
type IndexService struct {
WriteActive bool `gorm:"not null,DEFAULT false"`
}
Related
everyone,
I would like an advice on best practice for creating realtional database structure with field having mixed data type.
I have 'datasets' (some business objects) and I would like to have list of parameters, associated with each dataset. And those parameters can have different types - strings, integers, float and json values.
What would be the best structure for the parameters table? Should I have single column with string type?
CREATE TABLE param_desc (
id serial PRIMARY KEY,
name varchar NOT NULL,
param_type int -- varchar, int, real, json
);
CREATE TABLE param_value (
id serial PRIMARY KEY,
dataset_id int NOT NULL,
param int NOT NULL REFERENCES param_desc (id),
value varchar NOT NULL,
CONSTRAINT _param_object_id_param_name_id_time_from_key UNIQUE (dataset_id, param)
);
The problem with such approach is that I can't easily cast value for some additional conditions. For example, I want to get all datasets with some specific integer parameter, having int value more than 10. But if I write where clause, the casting will return error, as other non-integer parameters can't be casted.
SELECT dataset_id FROM vw_param_current WHERE name = 'priority' AND value::int > 5
Or should I have 4 separate columns, with 3 of them being NULL for every row?
Or should I have 4 different tables?
I'm using GORM to handle my database operations. My struct is as follows
type Job struct {
gorm.Model
JobID int `gorm:"primary_key"`
Jobitem []Jobitem
SubID int `sql:"not null"`
StartDateTime string `sql:"not null"`
JobStatus string `sql:"not null"`
}
When I insert into the table using this struct, my primary key is 18 digits long, for example: 399758776912773121
Is it possible to get this id to begin at 1 and increment from there?
You're using both gorm.Model and defining your own primary key. So my guess is that gorm automatically thinks you're trying to use Composite Primary Key, since your struct actually looks like this:
type Job struct {
// gorm.Model ↓
ID uint `gorm:"primary_key"` // Gorm uses this
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time `sql:"index"`
// gorm.Model ↑
JobID int `gorm:"primary_key"` // And also detects this
Jobitem []Jobitem
SubID int `sql:"not null"`
StartDateTime string `sql:"not null"`
JobStatus string `sql:"not null"`
}
Long story short, have a look there for some documentation on gorm.Model
Thanks Depado,
It looks like this is built in behavior by the database and not specifically related to GORM. The ID fields are generated using the unique_rowid() function in cockroachdb which is generated by a combination of the timestamp and id of the node executing the insert.
Here the code is written in Go. I am using two tables where one table has a foreign key that refers to the other table's primary key. Let's say I have a database as following struct defined:
type User struct{
ID uint `gorm:"primary_key;column:id"`
Name string `gorm:"column:name"`
Place place
PlaceID
}
type Place struct{
ID uint `gorm:"primary_key;column:id"`
Name string `gorm:"column:name"`
Pincode uint `gorm:"column:pincode"`
}
And the sql schema is:
create table place(
id int(20) NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
pincode uint(20) NOT NULL,
PRIMARY KEY (id),
)
create table user(
id int(20) NOT NULL AUTO_INCREMENT,
name varchar(100) NOT NULL,
place_id uint(20) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (place_id) REFERENCES place(id)
)
Now while inserting in user by gorm as:
place := Place{Name:"new delhi",Pincode:1234}
user := User{Name: "sam", Age: 15, Place: place}
err = db.Debug().Create(&user).Error
//It inserts to both user and place table in mysql
//now while updating to name in user table as Samuel and place as
//following
place := Place{Name:"mumbai",Pincode:1234}
err = db.Debug().Model(&User{}).Where("id =?",
1,).Update(&user{Name:"Samuel",Place:place}).Error
It updates the row in user table but creates a new row in place table.But it should update the matching row in place table and not create a new one
Is there any way to do it? Here I am not using auto migrate function to create db tables.
The answer to your question should be sought in a relations or Association Mode.
The example below shows how to add new associations for many to many, has many, replace current associations for has one, belongs to
db.Model(&user).Association("Place").Append(Place{Name:"mumbai",Pincode:1234})
Or you can replace current associations with new ones:
db.Model(&user).Association("Place").Replace(Place{Name:"mumbai",Pincode:1234},Place{Name:"new delhi",Pincode:1234})
Probably It's creating a new row because you didn't set the ID on Place{Name:"mumbai",Pincode:1234}.
I am trying to create a simple SQLite database that will allow me to store email addresses and timestamps. I have created the table like this:
$sql =<<<EOF
CREATE TABLE ENTRIES
(ID INT PRIMARY KEY NOT NULL,
EMAIL EMAIL NOT NULL,
TIMESTAMP DATETIME DEFAULT CURRENT_TIMESTAMP);
EOF;
And I am trying to insert an email like this:
$sql =<<<EOF
INSERT INTO ENTRIES (EMAIL)
VALUES (test#test.com);
EOF;
I am getting an error
NOT NULL constraint failed: ENTRIES.ID
I am assuming this is to do with the ID and autoincrement? I have read the docs and it advises against using autoincrement. Where am I going wrong?
The docs say:
If a table contains a column of type INTEGER PRIMARY KEY, then that column becomes an alias for the ROWID.
And because it becomes an alias for the ROWID, it's not necessary to explicitly specify a value.
You have INT PRIMARY KEY, not INTEGER PRIMARY KEY. If you change it to INTEGER PRIMARY KEY, it works the way you expect.
I have 2 tables as follows:
create table Users
(
UserId int primary key identity not null
)
create table UserExternalKeys
(
UserIdRef int primary key not null,
ExternalKey varchar(50) unique not null
)
alter table UserExternalKeys
add constraint fk_UsersExternalKeys_Users
foreign key (UserIdRef)
references Users (UserId)
Each user can have a 0 or 1 external keys. Things are setup this way because adding a nullable unique column to SQL Server does not allow for more than 1 null value.
Based on Ayende's post, it seems like this could be handled using a <one-to-one> mapping. However, this would require the UserExternalKeys table to have its own primary key.
The new schema would look something like this:
create table Users
(
UserId int primary key identity not null,
ExternalKeyRef int null
)
create table UserExternalKeys
(
UserExternalKeyId int primary key identity not null,
ExternalKey varchar(50) unique not null
)
alter table Users
add constraint fk_Users_UsersExternalKeys
foreign key (ExternalKeyRef)
references UserExternalKeys (UserExternalKeyId)
I think this would work, but it feels like I would only be adding the UserExternalKeyId column to appease NHibernate.
Any suggestions?
If a user can have 0 or 1 external keys why not design the tables as:
create table Users
(
UserId int primary key identity not null
ExternalKey varchar(50) null
)
and use one of the known workarounds for this problem. If you're using SQL Server 2008 you can use a filtered index. If you're using an earlier version you can use a trigger, an indexed view (2005), or the nullbuster workaround.
You could also keep your original schema and map the relationship as one-to-many from Users to UserExternalKeys. Map the collection as a private member and expose access to it through a property:
private IList<UserExternalKeys> _externalKeys;
public string ExternalKeys
{
get
{
if (_externalKeys.Count() == 1)
{
return _externalKeys.ElementAt(0).ExternalKey;
}
else
{
// return null or empty string if count = 0, throw exception if > 1
}
}
set
{
if (_externalKeys.Count() == 0) { // add key and set value }
else { // set value if count = 1, throw exception if > 1 }
}
}