GORM Save( ) is not returning Primary Key

Hello Guys, I’ve started to learn GORM by http://jinzhu.me/gorm/ . I have question or it could be an issue. So look at carefully.

The hibernate is ORM framework in java. In Hibernate, we are saving the object by creating the session like

              Transaction tx1 = session.beginTransaction();
	          Session session1 = sessionFactory.openSession();
	          Employee emp = new Employee();
              emp.SetName("John");
              emp.SetAddress("California");
	          long id1 = (Long) session1.save(emp);
              tx1.commit();

So this save( ) returns primary key and will be persisted into database. But in this GORM it is not returning anything.

          Db.Save(&empDTO)     //Kindly check it is not returning primary key

Again if we returned this saved record to Service layer and tried to set value like empDTO.setEmail("john@hotmail.com") then Hibernate will automatically inserting this change into database by internally executing query which is not happening in this GORM.

So kindly asking you all I anybody knows how to deal with this , post your answer as I am facing this kind of difficulty in my current project

Are you looking for Create()?

Yes Mr. Jakob. I’m trying to create/save record and expecting primary key to return.

And did you try using Create() as I linked to in the documentation?

Another thing to know about GORM that is incredibly helpful, if you add the Debug() function in your chain it will spit the generated SQL into the console so you can see exactly what it is doing.

Yes Mr.Jakob.I followed the same approach.

Yes you are right. Debug( ) function will give you the generated SQL on console.

Does anybody knows solution to this?

I think you’ll have to make a reproducible example, show your structs and your code. Create() is supposed to populate the primary key, and if it doesn’t do that for you we can work with your code to find out why.

By “reproducible example” I don’t mean loose snippets of your larger program, but a small test program that in itself shows the problem that we can run ourselves to see the behavior.

Yeah anything further we’d have to see your code to be honest. We don’t know what the employee struct you are using looks like, or if your fields are exported or not. I’m going to take a crack at it and say if you are hoping to assign that id to a long on the call, such as you have
long id1 = (Long) session1.save(emp);
That won’t do in go, the id will be returned to the employee struct’s ID field.

Hello Mr. Jakob , Sorry for the late reply. Kindly check the sample code herewith and If found mistakes or some modifications, suggest it.

Here is the sample code which is I’m using

                   package main
                   import (
                   _ "database/sql"
                   _ "github.com/go-sql-driver/mysql"
                   "github.com/jinzhu/gorm"
                   "log"
                   )

                  type User struct {
                       UserId   int `gorm:"primary_key"` //It will create UserId as primary key
                       Email    string
                       Password string
                  }

                  func main() {
                  Db, err := gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/employeedb?charset=utf8&parseTime=True")
                  /*In above line employeedb is my dbschema/database name */
          	      if err != nil {
	                  log.Fatal(err)
                  }
                  defer Db.Close()
                  Db.DropTableIfExists(&User{})      //Optional;If you want to drop existing table
                  Db.AutoMigrate(&User{})

                  //Saving record to Database
                  user := User{Email: "golang@gmail.com", Password: "golang"}
                  newUser := User{Email: "google@gmail.com", Password: "google"}
                  resultCreate := Db.Debug().Create(&user)
                  resultSave := Db.Debug().Save(&newUser)
                  Db.Debug().NewRecord(user)
                  log.Println(resultCreate)
                  log.Println(resultSave)
                 }

If anything needed from my side, let me know.

Your code is fine, you’re just not looking at the UserId.

user := User{Email: "golang@gmail.com", Password: "golang"}
newUser := User{Email: "google@gmail.com", Password: "google"}

log.Println(user.UserId)        // => 0
log.Println(newUser.UserId)     // => 0

Db.Debug().Create(&user)
Db.Debug().Save(&newUser)

log.Println(user.UserId)        // => 1
log.Println(newUser.UserId)     // => 2

Ohoo Thanks. I’ve updated my http://jinzhu.me/gorm/ library and it is working. Thanks a lot Mr.Jakob and Ms. CurtGreen.

Bdw Could you tell me as I’ve mentioned in my 1st discussion why that empDTO is not persisting.Like if saved object empDTO returned to Service Layer (MVC Architecture) and done some changes in empDTO e.g empDTO.setEmail("john@hotmail.com") then why it is not storing updated values to database by keeping empDTO in session by internally executing query. Hibernate does like this.Kindly reply because this one is the serious issue I’m facing.

No idea, show some code.

Here is the code I’m sharing.It is the RESTful API application.

main.go

package main
import (
       "ZGolangBridge/controller"
       "ZGolangBridge/dao"
)

func main() {
dao.DBConfig()
controller.Main()
}

UserModel.go

package model

type UserModel struct {
UserId   int    `gorm:"primary_key"`
Email    string `json:"email"`
Password string `json:"password"`
}

func (u *UserModel) SetUserId(uid int) {
u.UserId = uid
}

func (u *UserModel) GetUserId() int {
return u.UserId
}

func (u *UserModel) SetPassword(password string) {
u.Password = password
}

func (u UserModel) GetPassword() string {
return u.Password
}

UserController.go

package controller

import (
"ZGolangBridge/model"
"ZGolangBridge/service"
"encoding/json"
"github.com/gorilla/mux"
"io/ioutil"
"net/http"
)

type UserController struct {
}

var UserService service.UserServiceImpl = service.UserServiceImpl{}

func Main() {
router := mux.NewRouter()
uc := UserController{}
router.HandleFunc("/user/signup", uc.SignUp) //.Methods("GET")
http.ListenAndServe(":8050", router)
}

func (user UserController) SignUp(writer http.ResponseWriter, req *http.Request) {
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
body, _ := ioutil.ReadAll(req.Body)
var userModel1 model.UserModel
json.Unmarshal(body, &userModel1)
UModel := UserService.SaveUserInfo(userModel1)
resModel, _ := json.Marshal(UModel)
writer.Header().Set("Content-Type", "application/json")
writer.Write(resModel)
}

UserServiceImpl.go

package service

import (
"ZGolangBridge/dao"
"ZGolangBridge/model"
)

var UserDao dao.UserDAOImpl = dao.UserDAOImpl{}

type UserServiceImpl struct {
}

func (UService *UserServiceImpl) SaveUserInfo(userModel model.UserModel) model.UserModel {
var newUserModel model.UserModel
newUserModel = UserDao.SaveUser(userModel)

//newUserModel.SetEmail("martin@gmail.com")  //change will not reflect to DB like happens in hibernate

/* Here if I set any value to model like newUserModel.SetEmail("martin@gmail.com") then
this updated value should reflect in database by internally executing update query and keeping
in session like what Hibernate query is doing. You know in Hibernate when object is saved by using
Session.save(UserModel) as I have given example in 1st discussion post ,then Hibernate keeps this UserModel object in persistent state and if we try to
do changes to it then it will automatically update the values to database. But like Hibernate GORM is
not supporting this by keeping object in session. For this we need to write seperate update query if we
try to do changes to object*/

return newUserModel
}

UserDAOImpl.go

package dao

import (
"ZGolangBridge/model"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
"log"
)

type UserDAOImpl struct {
}

var Db *gorm.DB

func DBConfig() {
var err error
Db, err = gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/employeedb?charset=utf8&parseTime=True")
if err != nil {
	log.Print(err)
	return
}
Db.DropTableIfExists(&model.UserModel{})
Db.AutoMigrate(&model.UserModel{})
}

func (UDao *UserDAOImpl) SaveUser(userModel model.UserModel) model.UserModel {
Db.Save(&userModel)
return userModel
}

Kindly see the above code and revert back. If anything needed from my side,let me know.

GORM is not Hibernate.

func (UService *UserServiceImpl) SaveUserInfo(userModel model.UserModel) model.UserModel {
   var newUserModel model.UserModel
   newUserModel = UserDao.SaveUser(userModel)

   //newUserModel.SetEmail("martin@gmail.com")  //change will not reflect to DB like happens in hibernate

   /* Here if I set any value to model like newUserModel.SetEmail("martin@gmail.com") then
      this updated value should reflect in database by internally executing update query and keeping
      in session like what Hibernate query is doing. You know in Hibernate when object is saved by using
      Session.save(UserModel) then Hibernate keeps this UserModel object in persistent state and if we try to
      do changes to it then it will automatically update the values to database. But like Hibernate GORM is
      not supporting this by keeping object in session. For this we need to write seperate update query if we
      try to do changes to object*/

   return newUserModel
}

Calling newUserMode.SetEmail only modifies newUserModel. You have to save it to the DB yourself. Since the call to SaveUser happens before this call, the change is not saved to the DB because the code doesn’t do so.

Hello Mr.nathankerr, I agree with your point. Hibernate is doing the same so I asked this question in forum. Did you know any alternative to do like above ?

As far as I know, there is nothing like Hibernate for Go.

I think the main reason for this is that Hibernate needs to keep track of when things change, which means it needs to run code when a change is made. Go programs generally don’t use the accessor methods (e.g., SetEmail) that would be required to implement something like Hibernate.

While you could make this work by implementing the necessary logic in your DAO, I think it’s better to explicitly save to the DB.

2 Likes

Ok Mr. nathankerr, thanks for your valuable time and suggestions.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.