GORM Playground Link

https://github.com/go-gorm/playground/pull/266

Description

Hi, i'm trying to get rid of orphans for associations as soon as they are not in use anymore. So i would like to create a hook for this associated entity to remove it after the reference id is set to nil.

But i looks like hooks are not working for as expected for associations.

This not solved! As the updated association is not calling a hook.


So third try. You should really stop closing issues when they are not solved. You leave no room for discussions. This is a really bad habit.

But related to your again answer..

Yes maybe the aftercreate hook is called for the NEW entitiy.. But what about the OLD entity? Which is UPDATED by unsetting the reference id?? For this the updated hook should be called or not?

Comment From: jinzhu

We can't know the data is going to be inserted or updated when using the OnConflict, so we can't know which hooks methods should use especially the BeforeHooks.

For data that using Create with OnConflict option, we will use the create hooks for all of them, I think this make sense.

For your case, maybe you can use the BeforeSave hooks and check the field's value before reset it?


I will close those issues that I think GORM won't make any changes, or hard / time costing to maintain them.

Comment From: eloo

Okay.. and how can i get rid of the OnConflict stuff? This was not added by myself.

And if the hooks are not called everytime as expected (actually the entity is updated here) its pretty hard to rely on them. Further this drawback should be mentioned in the docs.

Maybe the implementation should be adjusted to check if the entity will be updated or inserted and call the hooks as expected.

Using the beforeSave hook for a replaced entity feels really weird.

In general this leaves the question open how orphans should be handled or better cleaned up directly. At the moment the implementation of gorm is creating a lot of orphans when you use associations.

Comment From: ghost

@jinzhu this is a major bug when using one-to-many associations... Sometimes we specifically want to create, sometimes its just updation... Having lot of orphans while using associations is gonna hinder many...

Comment From: jinzhu

Sometimes we specifically want to create, sometimes its just updation... Having lot of orphans while using associations is gonna hinder many...

I don't get why there will be orphans?

Comment From: ghost

I just checked @jinzhu , and I see there might not be much orphan issue. However calling the BeforeCreate hook is a major problem.. I personally use BeforeCreate to set some Default Values, and other checks to be done specifically on creation.. If this Hook gets called every time, it hinders the logic...

Comment From: jinzhu

However calling the BeforeCreate hook is a major problem

This is something not possible to fix, GORM can't know the data exists in db or not.

So would suggest you check if currently using the OnConflict mode or not by using _, ok := db.Statement.Clauses["ON CONFLICT"]

And check if current value exists or not before assign a new value.

Comment From: eloo

I don't get why there will be orphans?

not sure why you still are not getting this.

in my example you can cleary see that the old associated entity will be still in the database with the reference id null. and this is called an orphan. so every time you use this broken "replace" function you will get orphan entries in your database

Comment From: ghost

@jinzhu I am not familiar with the library code, however can we use this approach to identify if inserted or updated?

Comment From: jinzhu

in my example you can cleary see that the old associated entity will be still in the database with the reference id null. and this is called an orphan. so every time you use this broken "replace" function you will get orphan entries in your database

Replace doesn't delete old associations but only unset the reference id, this is by design to make sure data is safe, if you want to delete those orphan data, it is easy by doing:

db.Where("refer_id = ?", nil).Delete(&Association{})

I think this is not related to this issue?

@jinzhu I am not familiar with the library code, however can we use this approach to identify if inserted or updated?

This can only works with postgres, and even it works, it can't be used for Before Hooks...

Comment From: ghost

Replace doesn't delete old associations but only unset the reference id, this is by design to make sure data is safe

@jinzhu I belive this approach is wrong. For someone who uses the function, Association().Replace() - his thought will be that the existing rows will be deleted and the newer ones one will be created... It is also common practice to add multi-column constrains in a table.. Just setting up the reference key as NULL contradicts the general practice... If someone wants data safe option, he will use the Soft Delete option... Your assumption on just nullifying the foreign key is wrong in the practical sense

Comment From: Virtual-felix

I have the same issue, in an array of many-one association, if I remove an element it isn't removed when saving the parent. And I almost used Replace thinking it would remove all the child before re-inserting them. The fullSaveAssociation is really misleading as it only update the existing one, insert the new one but does not delete the one which does not exists anymore.... I still don't know how to do this properly if it is not by manually removing all the child before saving the parent.