I'm having trouble finding the right annotations for multiple has one which reference the same table. something like this:
type Pet struct {
gorm.Model
Name string
}
type PetOwner struct {
gorm.Model
LargestPet *Pet
SmallestPet *Pet
AllOthers []*Pet
}
Does anybody know what annotations and what explicit id fields would allow this to work?
Many thanks!
I got this working as follows:
type PetOwner struct {
gorm.Model
LargestPetID uint
LargetPet *Pet `gorm:"foreignKey:LargestPetID`
SmallestPetID uint
SmallestPet *Pet `gorm:"foreignKey:SmallestPetID`
AllOthers []*Pet
}
and then loading the data as follows:
var petOwner PetOwner
db.Joins("AllOthers").Joins("SmallestPet").Joins("LargestPet").Find(&petOwner)
If you want to access from the pet for which owner it is the largest pet, you can modify the pet definition as follows:
type Pet struct {
gorm.Model
...
LargestPetOf *PetOwner `gorm:"foreignKey:LargestPetID"
}
and then load this with a .Join("LargestPetOf")
Related
I have a list for example of type People. My list can contain only elements of type Student or only elements of type Worker:
interface People {
val name: String
val age: Int
}
data class Student(
override val name: String,
override val age: Int,
val course: Int
) : People
data class Worker(
override val name: String,
override val age: Int,
val position: String
) : People
At some point I need to know the exact type of the list (student or worker).
Can I safely find out the exact type? So far I've written this code, but it doesn't look very good:
fun someLogic(items: List<People>): List<People> {
return (items as? List<Student>) ?: (items as? List<Worker>)
?.filter {}
....
}
Also, I get a warning:
Unchecked cast
Can you please tell me how to perform such transformations correctly?
At runtime, the type parameter you used to create the list is not available. e.g. it is impossible to distinguish between the following two situations:
val students: List<People> = listOf<Student>(student1, student2)
val people: List<People> = listOf<People>(student1, student2)
This is because of type erasure.
The only information you have at runtime that can help determine a list's element type is the type of its elements.
So if a list has no elements, there is no way of knowing what type of list it is. Though in most situations, you don't need to anyway.
So assuming the list can only be a list of all students, or a list of all workers, but not a list containing a mixture of students and workers, you can determine the type of the list by checking the first element.
when (items.firstOrNull()) {
null -> { /* cannot determine the type */ }
is Student -> { /* is a list of students */ }
is Worker -> { /* is a list of worker */ }
// you can remove this branch by making the interface sealed
else -> { /* someone made another class implementing People! */ }
}
If you want to get a List<Student> or List<Worker> out of this on the other hand, you can just use filterIsInstance:
val students = items.filterIsInstance<Student>()
val worker = items.filterIsInstance<Worker>()
whichever list is not empty, then the type of items is the type of that list.
If you want to check that List<People> is List<Student> you can use this extension function:
fun List<People>.isStudentList(): Boolean {
// returns true if no element is not Student, so all elements are Student
return all { it is Student }
}
And if you want to cast List<People> to List<Student>, you can use map, and this cast is safe so let's say that there is some People that the are not Student so the cast is going to return null instead of Student because of as? and the mapNotNull is going to exclude null elements so in worst cases where you pass a list that doesn't contain any Student this function is going to return an empty list:
fun List<People>.toStudentList(): List<Student> {
// This is going to loop through the list and cast each People to Student
return mapNotNull { it as? Student }
}
Or you can just use filterIsInstance<Student> this will work the same as toStudentList above:
list.filterIsInstance<Student>()
And the same approach can be used for Worker
I would solve the problem with more specific classes.
You can define:
interface PeopleList<P : People> : List<P>
class StudentList : PeopleList<Student> {
// add implementation
}
class WorkerList : PeopleList<Worker> {
// add implementation
}
You can then easily check the types of these lists. Each of those classes can then provide guarantees that you are not mixing Student and Worker objects in the same List, something you can't do with plain List<People> objects.
Note also you are better off writing your code avoiding checking types if at all possible. Much better to add methods to the PeopleList interface and force the subclasses to implement them, for example:
interface PeopleList<P : People> : List<P> {
fun doSomethingGood()
}
Then you can call these methods at the appropriate time, instead of checking the type. This approach keeps the functionality associated with the subtypes alongside those subtypes and not scattered through the code at the various points where you have to check the type of PeopleList.
I guess I got stuck in thinking about a polymorphism solution to my following problem:
Let's say I have a BaseTX struct with fields for a transaction. Now I have two special types of transactions: RewardTX struct and AllowanceTX struct.
RewardTX struct has at this moment only the composition of BaseTX struct.
AllowanceTX struct has a composition of BaseTX struct and an AddField.
I have also a function logicAndSaveTX(), which has some logic on fields from BaseTX but at the end is serializing the whole object using json.Marshal() and saving the byte[] somewhere.
type TXapi interface {
logicAndSaveTX()
}
type BaseTX struct {
Field1 string
Field2 string
}
type RewardTX struct {
BaseTX
}
type AllowanceTX struct {
BaseTX
AddField string
}
func (tx BaseTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
func SaveTX(tx TXapi) {
tx.logicAndSaveTX()
}
func main() {
rewardTX := RewardTX{BaseTX : BaseTX{Field1: "Base info1", Field2: "Base info2"}}
SaveTX(rewardTX) // should print rewardTX with fields from BaseTX
allowanceTX := AllowanceTX{BaseTX : BaseTX{Field1: "Base info1", Field2: "Base info2"}, AddField: "additional field"}
SaveTX(allowanceTX) // would like to print allowanceTX with fields from BaseTX + AdditionalField >>> instead only printing fields from BaseTX
}
https://play.golang.org/p/0Vu_YXktRIk
I try to figure out how to implement the structures and the function to operate on both kinds of transactions but at the end serializing both structures properly. My problem is, that the AddField is not being seen in my current implementation.
Maybe I have got some brain fail here--I would really like to implement this the "proper Go way". :)
Go is not object-oriented. The only form of polymorphism in Go is interfaces.
Coming from other, object-oriented languages can be difficult, because you have to get rid of a lot of ideas you might try to carry over - things like, for example, "base" classes/types. Just remove "base" from your design thinking; you're trying to turn composition into inheritance, and that's only going to get you into trouble.
In this case, maybe you have a legitimate case for composition here; you have some common shared fields used by multiple types, but it's not a "base" type. It's maybe "metadata" or something - I can't say what to call it given that your example is pretty abstract, but you get the idea.
So maybe you have:
type TXapi interface {
logicAndSaveTX()
}
type Metadata struct {
Field1 string
Field2 string
}
type RewardTX struct {
Metadata
}
func (tx RewardTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
type AllowanceTX struct {
Metadata
AddField string
}
func (tx AllowanceTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
tx.AddField = "more stuff"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
If the handling of the metadata (or whatever) fields is identical in all uses, maybe you give that type its own logicTX method to fill those fields, which can be called by the logicAndSaveTX of the structs that embed it.
The key here is to think of the behavior (methods) on a type to be scoped to that type, instead of thinking of it as somehow being able to operate on "child types". Child types don't exist, and there is no way for a type that is embedded in another type to operate on its container.
Also point to be noted here aht Go only support run time polymorphism through interfaces. Compile time polymorphism is not possible in Golang.
Source: - https://golangbyexample.com/oop-polymorphism-in-go-complete-guide/
I'm trying to clean up my code base by doing a better job defining interfaces and using embedded structs to reuse functionality. In my case I have many entity types that can be linked to various objects. I want to define interfaces that capture the requirements and structs that implement the interfaces which can then be embedded into the entities.
// All entities implement this interface
type Entity interface {
Identifier()
Type()
}
// Interface for entities that can link Foos
type FooLinker interface {
LinkFoo()
}
type FooLinkerEntity struct {
Foo []*Foo
}
func (f *FooLinkerEntity) LinkFoo() {
// Issue: Need to access Identifier() and Type() here
// but FooLinkerEntity doesn't implement Entity
}
// Interface for entities that can link Bars
type BarLinker interface {
LinkBar()
}
type BarLinkerEntity struct {
Bar []*Bar
}
func (b *BarLinkerEntity) LinkBar() {
// Issues: Need to access Identifier() and Type() here
// but BarLinkerEntity doesn't implement Entity
}
So my first thought was to have FooLinkerEntity and BarLinkerEntity just implement the Entity interface.
// Implementation of Entity interface
type EntityModel struct {
Id string
Object string
}
func (e *EntityModel) Identifier() { return e.Id }
func (e *EntityModel) Type() { return e.Type }
type FooLinkerEntity struct {
EntityModel
Foo []*Foo
}
type BarLinkerEntity struct {
EntityModel
Bar []*Bar
}
However, this ends up with an ambiguity error for any types that can link both Foos and Bars.
// Baz.Identifier() is ambiguous between EntityModel, FooLinkerEntity,
// and BarLinkerEntity.
type Baz struct {
EntityModel
FooLinkerEntity
BarLinkerEntity
}
What's the correct Go way to structure this type of code? Do I just do a type assertion in LinkFoo() and LinkBar() to get to Identifier() and Type()? Is there any way to get this check at compile time instead of runtime?
Go is not (quite) an object oriented language: it does not have classes and it does not have type inheritance; but it supports a similar construct called embedding both on struct level and on interface level, and it does have methods.
So you should stop thinking in OOP and start thinking in composition. Since you said in your comments that FooLinkerEntity will never be used on its own, that helps us achieve what you want in a clean way.
I will use new names and less functionality to concentrate on the problem and solution, which results in shorter code and which is also easier to understand.
The full code can be viewed and tested on the Go Playground.
Entity
The simple Entity and its implementation will look like this:
type Entity interface {
Id() int
}
type EntityImpl struct{ id int }
func (e *EntityImpl) Id() int { return e.id }
Foo and Bar
In your example FooLinkerEntity and BarLinkerEntity are just decorators, so they don't need to embed (extend in OOP) Entity, and their implementations don't need to embed EntityImpl. However, since we want to use the Entity.Id() method, we need an Entity value, which may or may not be EntityImpl, but let's not restrict their implementation. Also we may choose to embed it or make it a "regular" struct field, it doesn't matter (both works):
type Foo interface {
SayFoo()
}
type FooImpl struct {
Entity
}
func (f *FooImpl) SayFoo() { fmt.Println("Foo", f.Id()) }
type Bar interface {
SayBar()
}
type BarImpl struct {
Entity
}
func (b *BarImpl) SayBar() { fmt.Println("Bar", b.Id()) }
Using Foo and Bar:
f := FooImpl{&EntityImpl{1}}
f.SayFoo()
b := BarImpl{&EntityImpl{2}}
b.SayBar()
Output:
Foo 1
Bar 2
FooBarEntity
Now let's see a "real" entity which is an Entity (implements Entity) and has both the features provided by Foo and Bar:
type FooBarEntity interface {
Entity
Foo
Bar
SayFooBar()
}
type FooBarEntityImpl struct {
*EntityImpl
FooImpl
BarImpl
}
func (x *FooBarEntityImpl) SayFooBar() {
fmt.Println("FooBar", x.Id(), x.FooImpl.Id(), x.BarImpl.Id())
}
Using FooBarEntity:
e := &EntityImpl{3}
x := FooBarEntityImpl{e, FooImpl{e}, BarImpl{e}}
x.SayFoo()
x.SayBar()
x.SayFooBar()
Output:
Foo 3
Bar 3
FooBar 3 3 3
FooBarEntity round #2
If the FooBarEntityImpl does not need to know (does not use) the internals of the Entity, Foo and Bar implementations (EntityImpl, FooImpl and BarImpl in our cases), we may choose to embed only the interfaces and not the implementations (but in this case we can't call x.FooImpl.Id() because Foo does not implement Entity - that is an implementation detail which was our initial statement that we don't need / use it):
type FooBarEntityImpl struct {
Entity
Foo
Bar
}
func (x *FooBarEntityImpl) SayFooBar() { fmt.Println("FooBar", x.Id()) }
Its usage is the same:
e := &EntityImpl{3}
x := FooBarEntityImpl{e, &FooImpl{e}, &BarImpl{e}}
x.SayFoo()
x.SayBar()
x.SayFooBar()
Its output:
Foo 3
Bar 3
FooBar 3
Try this variant on the Go Playground.
FooBarEntity creation
Note that when creating FooBarEntityImpl, a value of Entity is to be used in multiple composite literals. Since we created only one Entity (EntityImpl) and we used this in all places, there is only one id used in different implementation classes, only a "reference" is passed to each structs, not a duplicate / copy. This is also the intended / required usage.
Since FooBarEntityImpl creation is non-trivial and error-prone, it is recommended to create a constructor-like function:
func NewFooBarEntity(id int) FooBarEntity {
e := &EntityImpl{id}
return &FooBarEntityImpl{e, &FooImpl{e}, &BarImpl{e}}
}
Note that the factory function NewFooBarEntity() returns a value of interface type and not the implementation type (good practice to be followed).
It is also a good practice to make the implementation types un-exported, and only export the interfaces, so implementation names would be entityImpl, fooImpl, barImpl, fooBarEntityImpl.
Some related questions worth checking out
What is the idiomatic way in Go to create a complex hierarchy of structs?
is it possible to call overridden method from parent struct in golang?
Can embedded struct method have knowledge of parent/child?
Go embedded struct call child method instead parent method
Seems to me having three ID in one structure with methods relying on them is even semantically incorrect. To not be ambiguous you should write some more code to my mind. For example something like this
type Baz struct {
EntityModel
Foo []*Foo
Bar []*Bar
}
func (b Baz) LinkFoo() {
(&FooLinkerEntity{b.EntityModel, b.Foo}).LinkFoo()
}
func (b Baz) LinkBar() {
(&BarLinkerEntity{b.EntityModel, b.Bar}).LinkBar()
}
I'm trying to separate my code into models and serializers with the idea that there be defined serializers that handles all json responsibilities, i.e. separation of concerns. I also want to be able to call a model object obj.Serialize() to get the serializer struct obj that I can then marshal. Therefore, I've come up with the following design. To avoid circular import I had to use interfaces in my serializers which leads to using getters in my models. I've read that getters/setters aren't idiomatic go code and I would prefer not to have "boilerplate" getter code all over my models. Is there a better solution to what I want to accomplish, keeping in mind I want separation of concerns and obj.Serialize()?
src/
models/
a.go
serializers/
a.go
models/a.go
import "../serializers"
type A struct {
name string
age int // do not marshal me
}
func (a *A) Name() string {
return a.name
}
// Serialize converts A to ASerializer
func (a *A) Serialize() interface{} {
s := serializers.ASerializer{}
s.SetAttrs(a)
return s
}
serializers/a.go
// AInterface used to get Post attributes
type AInterface interface {
Name() string
}
// ASerializer holds json fields and values
type ASerializer struct {
Name `json:"full_name"`
}
// SetAttrs sets attributes for PostSerializer
func (s *ASerializer) SetAttrs(a AInterface) {
s.Name = a.Name()
}
It looks like you are actually trying to translate between your internal structs and json. We can start by taking advantage of the json library.
If you want certain libraries to handle your struct fields in certain ways, there are tags. This example shows how json tags tell json to never marshal the field age into json, and to only add the field jobTitle if it is not empty, and that the field jobTitle is actually called title in json. This renaming feature is very useful when structs in go contain capitalized (exported) fields, but the json api you're connecting to uses lowercase keys.
type A struct {
Name string
Age int `json:"-"`// do not marshal me
location string // unexported (private) fields are not included in the json marshal output
JobTitle string `json:"title,omitempty"` // in our json, this field is called "title", but we only want to write the key if the field is not empty.
}
If you need to precompute a field, or simply add a field in your json output of a struct that isn't a member of that struct, we can do that with some magic. When json objects are decoded again into golang structs, fields that don't fit (after checking renamed fields and capitalization differences) are simply ignored.
// AntiRecursionMyStruct avoids infinite recursion in MashalJSON. Only intended for the json package to use.
type AntiRecursionMyStruct MyStruct
// MarshalJSON implements the json.Marshaller interface. This lets us marshal this struct into json however we want. In this case, we add a field and then cast it to another type that doesn't implement the json.Marshaller interface, and thereby letting the json library marshal it for us.
func (t MyStruct) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
AntiRecursionMyStruct
Kind string // the field we want to add, in this case a text representation of the golang type used to generate the struct
}{
AntiRecursionMyStruct: AntiRecursionMyStruct(t),
Kind: fmt.Sprintf("%T", MyStruct{}),
})
}
Keep in mind that json will only include your exported (capitalized) struct members. I've made this misstake multiple times.
As a general rule, if something seems too complicated, there's probably a better way to do it.
I'm experimenting with PetaPoco to convert a table into POCOs.
In my table, I've got a column named TheEnum. The values in this column are strings that represent the following enum:
public enum MyEnum
{
Fred,
Wilma
}
PetaPoco chokes when it tries to convert the string "Fred" into a MyEnum value.
It does this in the GetConverter method, in the line:
Convert.ChangeType( src, dstType, null );
Here, src is "Fred" (a string), and dstType is typeof(MyEnum).
The exception is an InvalidCastException, saying Invalid cast from 'System.String' to 'MyEnum'
Am I missing something? Is there something I need to register first?
I've got around the problem by adding the following into the GetConverter method:
if (dstType.IsEnum && srcType == typeof(string))
{
converter = delegate( object src )
{
return Enum.Parse( dstType, (string)src ) ;
} ;
}
Obviously, I don't want to run this delegate on every row as it'll slow things down tremendously. I could register this enum and its values into a dictionary to speed things up, but it seems to me that something like this would likely already be in the product.
So, my question is, do I need to do anything special to register my enums with PetaPoco?
Update 23rd February 2012
I submitted a patch a while ago but it hasn't been pulled in yet. If you want to use it, look at the patch and merge into your own code, or get just the code from here.
I'm using 4.0.3 and PetaPoco automatically converts enums to integers and back. However, I wanted to convert my enums to strings and back. Taking advantage of Steve Dunn's EnumMapper and PetaPoco's IMapper, I came up with this. Thanks guys.
Note that it does not handle Nullable<TEnum> or null values in the DB. To use it, set PetaPoco.Database.Mapper = new MyMapper();
class MyMapper : PetaPoco.IMapper
{
static EnumMapper enumMapper = new EnumMapper();
public void GetTableInfo(Type t, PetaPoco.TableInfo ti)
{
// pass-through implementation
}
public bool MapPropertyToColumn(System.Reflection.PropertyInfo pi, ref string columnName, ref bool resultColumn)
{
// pass-through implementation
return true;
}
public Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo pi, Type SourceType)
{
if (pi.PropertyType.IsEnum)
{
return dbObj =>
{
string dbString = dbObj.ToString();
return enumMapper.EnumFromString(pi.PropertyType, dbString);
};
}
return null;
}
public Func<object, object> GetToDbConverter(Type SourceType)
{
if (SourceType.IsEnum)
{
return enumVal =>
{
string enumString = enumMapper.StringFromEnum(enumVal);
return enumString;
};
}
return null;
}
}
You're right, handling enums is not built into PetaPoco and usually I just suggest doing exactly what you've done.
Note that this won't slow things down for requests that don't use the enum type. PetaPoco generates code to map responses to pocos so the delegate will only be called when really needed. In other words, the GetConverter will only be called the first time a particular poco type is used, and the delegate will only be called when an enum needs conversion. Not sure on the speed of Enum.Parse, but yes you could cache in a dictionary if it's too slow.
If you are using PetaPoco's T4 generation and you want enums in your generated type, you can use the PropertyType override in Database.tt:
tables["App"]["Type"].PropertyType = "Full.Namespace.To.AppType";
I you want to store the value of the enum instead of the index number (1,2,4 for example) you can locate the update function in PetaPoco class because the code is "managed" etc, when you add it as nuget package it will store the .cs file to your project. If we would have the enum variable Color = {red, yellow, blue}
Instead of:
// Store the parameter in the command
AddParam(cmd, pc.GetValue(poco), pc.PropertyInfo);
change to:
//enum?
if (i.Value.PropertyInfo.PropertyType.IsEnum)
{
AddParam(cmd, i.Value.GetValue(poco).ToString(), i.Value.PropertyInfo);
}
else
{
// Store the parameter in the command
AddParam(cmd, i.Value.GetValue(poco), i.Value.PropertyInfo);
}
It would store "yellow" instead of 2