Open lunemec opened 6 years ago
Depending on how performant you need to be, you could use Gorm which disperses of the need for sql null types.
We are using gorm, and it has its own set of problems. For example:
// db is gorm.DB
var out mysql.Organization
err := db.Where(mysql.Organization{ID: someID}).Assign(mysql.Organization{Name: "NewName"}).FirstOrCreate(&out).Error
if err != nil {
return err
}
Problem with this is that if your someID
variable is 0 - zero value for int, this query produces this SQL:
SELECT * FROM organization LIMIT 1; // FirstOrSelect part to select if record exists
UPDATE organization SET .... WHERE id=1; // Update first record. ALWAYS.
With incorrect WHERE clause, because the mysql.Organization structure passed to Where()
is indistinguishable from its zero value. We found out and fixed this bug by using it like this:
err := db.Assign(mysql.Organization{Name: "NewName"}).FirstOrCreate(&out, someID).Error
It was bug in our code. We misunderstood how it is supposed to be used, but the more we use it, the more we wish we'd use simple SQL without ORM.
have you tried sqlx? It has a nice StructScan function but you get to write real SQL
@the-destro yes, I know of sqlx. It is a great library, but I don't think it would help here much.
Each model is duplicated at least twice. In generic model that is used to pass data between layers and DB specific model containing
sql.Null*
types ormysql.NullTime
or such.Also this forces us to write
ToModel()
andFromModel
methods to convert into "generic" model. This is terrible code smell. It leads to duplicits and having to write conversions manually. Breaks DRY principle.Every model change requires change in several places which leads to bugs.
model/organization.go model/mysql/organization.go