How to get auto-generated row primary key via Ruby PostgreSQL gem? - ruby

My table in PostgreSQL looks like this:
CREATE TABLE user (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL
)
I'm using Ruby pg gem to add a record to the table:
c = PG.connect(dbname: 'foo')
id = c.exec_params('INSERT INTO user (name) VALUES ($1)', ['Jeff']).oid_value
I'm getting nil back, instead of the auto-generated id of the new record. What is the right way to get it back?

According to the docs, if the object id you're retrieving isn't set, thus nil.
You either have to set the object id yourself, or use returning like this:
res = conn.exec("INSERT INTO users (name) VALUES ('john') returning id")
res[0]['id']
#=> 1

Related

Spring Repository save() method doesn't return the rounded value

Save() returns the saved object with wrong attributes, the attribute "price" should return a rounded value.
Let's say I have the following table:
CREATE TABLE OBJ(
ID INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30) NOT NULL,
DESCRIPTION VARCHAR(200) NOT NULL,
PRICE DECIMAL(10,2) NOT NULL,
);
If I do:
Obj newobj = new Obj("obj name", "brief description", 12.555);
repository.save(newObj);
Looking into the database, the object was saved correctly, so the price saved is 12.56 but method save() has returned the saved object with price = 12.555. Could this behavior be a bug?
Could this behaviour be a bug?
No.
This is the expected behaviour.
The only value that gets returned after it was modified by the database is the id.
If you want such values to get updated you need to require from the database.
When doing so you'll have to makes sure to do so without the entity being in the persistence context, to avoid the 1st level cache to interfere with your attempt to reload the entity.
As far as I understand the problem is about the value stored into the database and in order to fix it you have to replace PRICE DECIMAL(10,2) NOT NULL with PRICE DECIMAL(10,3) NOT NULL. Then the stored value will retain 3 digits after comma.

Golang gorm preloading

I'm writing my first app in golang, so sorry for newbie question, but I wasn't able to find the solution for the following problem:
I have two tables, position and attachment. Each position can have multiple attachments. Here is my model:
type Positions struct {
Sys_id int `gorm:"AUTO_INCREMENT" gorm:"column:sys_id" json:"sys_id,omitempty"`
Name string `gorm:"size:120" gorm:"column:name" json:"name,omitempty"`
OpenPositions int `gorm:"column:open_positions" json:"open_positions,omitempty"`
ContactList string `gorm:"size:1000" gorm:"column:contact_list" json:"contact_list,omitempty"`
Attachments []Attachment `gorm:"ForeignKey:RecordId"`
}
type Attachment struct {
Sys_id int `gorm:"AUTO_INCREMENT" gorm:"column:sys_id" json:"sys_id"`
Name string `gorm:"size:255" gorm:"column: name" json:"name"`
File string `gorm:"size:255" gorm:"column:file" json:"file"`
RecordId int `gorm:"column:record_id" json:"record_id"`
Table string `gorm:"size:255" gorm:"column:table" json:"table"`
// ...
}
I want to query the db and get positions with attachments
positions2 := []models.Positions{}
err := db.Where("open_positions > ?", 0).Preload("Attachments", "`table` = ?", "user_position").Find(&positions2)
if err != nil {
log.WithFields(log.Fields{
"type": "queryerr",
"msg": err,
}).Error("faked up query")
}
Result of this query - I get positions correctly but the attachments are empty.
(can't preload field Attachments for models.Positions)
level=error msg="faked up query" msg=&{0xc04200aca0 can't preload field Attachments for models.Positions 6 0xc042187e40 0xc042187d90 0xc0422cd4a0 0 {0xc042225130} false map[] map[] false}
Thanks in advance for help
Models in your example have custom primary column names.
So, when only ForeignKey set for "has_many" association, Gorm trying to find Position's column Attachment.RecordId refers to.
By default it uses Position as prefix and Id as column name for this. But neither RecordId column has prefix Position nor Position model has column Id, so it fails.
In such case for "has_many" association you should specify both Foreign Key and Association Foreign Key.
In your example Association Foreign Key is the Position.Sys_id column and Attachment.RecordId refers to it.
So it should be fixed just by adding Association foreign key:
Attachments []Attachment `gorm:"ForeignKey:RecordId;AssociationForeignKey:sys_id"`
Looks like it is not about Go or Gorm but about SQL.
W3SCHOOLS:
A FOREIGN KEY in one table points to a PRIMARY KEY in another table.
But RecordId is not a primary key in your model. Let the foreign key refer to a primary key. It should be fixed with:
RecordId int `gorm:"column:record_id" gorm:"primary_key" json:"record_id"`

Slick/Oracle PLAIN SQL Get auto generated ID after insert

I am trying to run a query via Slick in Scala that will insert a record into an Oracle db and return the auto generated ID as the result. I see that this is possible using Slick's syntax but is this possible using a plain SQL query? With below code I can only get a return value of -1.
val name = "Bob"
db.run(sql"""DECLARE NEW_PERSON_ID;
BEGIN
INSERT INTO TB_PEOPLE (ID, NAME)
VALUES(SEQ_PEOPLE.NEXTVAL, $name)
RETURNING ID INTO NEW_PERSON_ID;
END;""".as[Int])
It seems that Slick doesn't support output parameters so using Oracle's returning syntax won't work. A workaround I found is to first generate an ID and then insert using that ID (requires 2 queries). The queries are wrapped in a transaction.
val name = "Bob"
val action = for {
newPersonId <- sql"""SELECT SEQ_PEOPLE.NEXTVAL FROM DUAL""".as[Int]
_ <- sqlu"""INSERT INTO TB_PEOPLE (ID, NAME) VALUES ($newPersonId, $name)"""
}
db.run(action.transactionally)

Sequel Migration update with a row's ID

How can you run a Sequel migration that updates a newly added column with a value from the row?
The Sequel documentation shows how you can update the column with a static value:
self[:artists].update(:location=>'Sacramento')
What I need to do is update the new column with the value of the ID column:
something like:
self[:artists].each |artist| do
artist.update(:location => artist[:id])
end
But the above doesn't work and I have been unable to figure out how to get it to go.
Thanks!
artist in your loop is a Hash, so you are calling Hash#update, which just updates the Hash instance, it doesn't modify the database. That's why your loop doesn't appear to do anything.
I could explain how to make the loop work (using all instead of each and updating a dataset restricted to the matching primary key value), but since you are just assigning the value of one column to the value of another column for all rows, you can just do:
self[:artists].update(:location=>:id)
if you need update all rows of a table, because it is a new column that need be populate
artists = DB[:artists]
artists.update(:column_name => 'new value')
or if you need, update only a unique row into your migration file you can:
artists = DB[:artists]
artists.where(:id => 1).update(:column_name1 => 'new value1', :column_name2 => "other")

How to get next id in GRAILS?

I need to get the next available id in a sequence, using GORM or native query.
How can I do this?
I'm using oracle.
UPDATE:
I need this value BEFORE insert, because my row will use this value.
I have table called IMAGE, with column FILE_NAME, like this:
- ID | FILE_NAME
- 123 | foo_bar_123.png
- 124 | xxx_yyy_124.png
Tks a lot.
Why do you need the value before the insert? Could you get the information as part of the insert using the RETURNING clause, i.e.
INSERT INTO table_name( id, file_name )
VALUES( some_sequence.nextval, <<bind variable>> )
RETURNING id INTO <<bind variable>>
Or access it after the insert using
SELECT sequence_name.currval
FROM dual
The currval of a sequence returns the most recent value of the sequence produced in the current session so it is actually thread-safe. Since sequences are designed to provide numbers in a highly concurrent environment, you cannot in general find out what the nextval is going to be unless you actually fetch the nextval. Even if you could, there is no guarantee that another thread won't come along and get the value you peeked at before your INSERT took place so it wouldn't be safe to peek at the nextval in a multi-user environment.
I adapted #Cave tips.
So, my solution is:
Change my mapping from:
class Image {
...
id column: "ID", generator: "sequence", params: [sequence:"MY_SEQUENCE"]
...
}
to:
class Image {
...
id column: "ID", generator: "assigned"
...
}
And set id mannualy using this:
def getLastImageId(){
def sql = "SELECT MY_SEQUENCE.nextval FROM dual"
def query = sessionFactory.currentSession.createSQLQuery(sql);
def result = query.list()
return result[0]
}
...
newImage.id = getLastImageId()
newImage.fileName = "foo_bar_${newImage.id}.png"

Resources