go-gorm / gorm

The fantastic ORM library for Golang, aims to be developer friendly
https://gorm.io
MIT License
36.95k stars 3.93k forks source link

polymorphic associations #238

Closed ronna-s closed 9 years ago

ronna-s commented 10 years ago

Any plans to add polymorphic associations?

jinzhu commented 10 years ago

It is not planed, still don't have any idea about how the API would looks like.

Please let me know if you have any suggestions

jnfeinstein commented 9 years ago

+1, I'm going to need this as well. I was thinking of adding a gorm directive like many2many, maybe polymorphic=XYZ if that's possible. XYZ_id would be filled in by the object's ID, and XYZ_type would be the object's type.

wyattjoh commented 9 years ago

Also would be interested in this feature, not sure if there is a work around for the moment or not.

wyattjoh commented 9 years ago

As a workaround I suppose, one could:

type Cat struct {
    ID int64
}

type Dog struct {
    ID int64
}

type Category struct {
    ID int64
}

type Follower struct {
    FollowerID int64
    FollowerName string
    CategoryID int64
}

cat = Cat{1}
category = Category{1}
follower = Follower{
    FollowerID: cat.ID,
    FollowerName: 'Cat',
    CategoryID: category.ID,
}

But then reversing this seems a bit irritating... Not sure, just a thought.

jnfeinstein commented 9 years ago

I've started working on this, and I found the following API to be easy to work with:

var Cat struct {
  Id int
  Toy Toy `gorm:"foreignkey: owner_id; foreigntype: owner_type"`
}
var Toy struct {
  Id int
  Owner interface{} `gorm:"foreignkey: owner_id; foreigntype: owner_type"`
  OwnerId int
  OwnerType string
}

var toys []Toy
DB.Model(&Cat{}).Association("Toy").Find(&toys)

The weird thing is implementing belongs_to or many_to_many, since the receiving object can be typed. many_to_many is a bit easier to comprehend since you just look in the join table for anything of the receiving type. However belongs_to is throwing me for a mental curveball. I guess you'd straight up return RecordNotFound and bypass querying if the receiving type doesn't match? If it's an interface, you'd have to use crazy reflection to assign it to the proper value.

jnfeinstein commented 9 years ago

Think I have this one on ice. Anyone care to take a look before I issue the pull request?

I didn't implement belongs-to and many-to-many, since it gets really with Go's typing. Instead it will throw errors telling you not to do that.

wyattjoh commented 9 years ago

I did take a browse, my particular use case actually requires a many to many relationship that is brokered by a polymorphic association. I needed to have many Businesses followed by many Users, but using the same relationship to allow many Users to follow many Categories.

jnfeinstein commented 9 years ago

I do have code that can do polymorphic many-to-many assuming that you give it a destination type. I wasn't able to find a way to dynamically create the typed structs from the field in the database. Ruby can, which is presumably why it works so well in ActiveRecord. So we could add code to say "find me all users that follow this category" or "find me all businesses that follow this category" but not "find me all things that follow this category".

wyattjoh commented 9 years ago

That would work I'd expect, most typed code would freak out at a magical object that is expected to be anything haha. So I think that the situation that you described @jnfeinstein would work for this.

jnfeinstein commented 9 years ago

Let's see what happens with #303 and go from there.

jinzhu commented 9 years ago

We have already merged this pull request long time ago, thanks @jnfeinstein

pdf commented 9 years ago

@jnfeinstein what about handling the other relationship types by requiring the user to implement an interface that can be satisfied by the polymorphic entities?