|
问题在Golang一对多或多对多的中处理SQL在关系中,将线映射到最佳结构(高效,推荐类似Go什么是方式?$ B% ?& j6 {) u& k" ? n
以下示例为例。我试图详细介绍每种方法的优缺点,但我想知道社区的建议是什么。& N# Q. Z Y2 C# i1 w5 M$ N
要求适用于PostgreSQL(可以通用,但不包括MySQL / Oracle特定功能), P3 R X* K/ f3 [: ]* @! D
效率-每种组合都不会被强迫. _$ Y% z( K( \0 T
没有ORM-仅在理想情况下使用database/sql和jmoiron/sqlx例子为了明确起见,我删除了错误的处理+ y8 B1 T, U, x$ x! T1 V" C
楷模
7 U2 x8 x q Y) A% ^type Tag struct { ID int Name string}type Item struct { ID int Tags []Tag}数据库
$ n" ^- j7 i) c3 v$ G+ n( vCREATE TABLE item ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY);CREATE TABLE tag ( id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(160), item_id INT REFERENCES item(id));方法1-选择所有项目,然后为每个项目选择标签+ I- i/ L. g5 A/ Q' { p
var items []Itemsqlxdb.Select(&items,"SELECT * FROM item")for i,item := range items { var tags []Tag sqlxdb.Select(&tags,"SELECT * FROM tag WHERE item_id = $1",item.ID) items<i>.Tags = tags}优点4 |* Q) V: N5 `7 @: L2 h6 }
简单的9 ^0 k# Z1 @, r+ R. B) Q
容易明白缺点
$ G# a- O. T( B4 ^4 t7 H( |. Z数据库查询数量与项目数量成正比方法2-构造SQL连接并手动遍历行! [4 J7 U2 G4 T& \
var itemTags = make(map[int][]Tag)var items = []Item{}rows,_ := sqlxdb.Queryx("SELECT i.id,t.id,t.name FROM item AS i JOIN tag AS t ON t.item_id = i.id")for rows.Next() { var itemID int tagID int tagName string ) rows.Scan(&itemID,&tagID,&tagName) if tags,ok := itemTags[itemID]; ok itemTags[itemID] = append(tags,Tag{ID: tagID,Name: tagName,}) } else itemTags[itemID] = []Tag{Tag{ID: tagID,Name: tagName,}} }}for itemID,tags := range itemTags { items = append(Item{ ID: itemID, Tags: tags, })}优点- i8 K# e% p; j) a& Q% |0 R
单个数据库调用和游标可以在不占用太多内存的情况下循环缺点( ^+ A' p9 j6 P2 H% u. Q' H
复杂且难以开发多个连接和结构的许多属性9 ~- Q: I, ]( @2 j. R: \
性能不好;更多的内存使用和处理时间,而不是更多的网络调用失败的方法3-SQLX结构扫描; N0 a* n' T- w) Q& c
虽然失败了,但我还是想包括这个方法,因为我发现它是我目前效率和发展简单性相结合的目标。我的希望是通过db标签设置在每个结构字段上sqlx可以扫描一些高级结构
5 D4 t. w0 E2 R0 E' pvar items []Itemsqlxdb.Select(&items,"SELECT i.id AS item_id,t.id AS tag_id,t.name AS tag_name FROM item AS i JOIN tag AS t ON t.item_id = i.id")不幸的是,这个错误使得missing destination name tag_id in*[]Item我相信消息StructScan还不够先进,不能递归历行(无可奉告-这是一个复杂的场景)9 S O, T5 j% r9 Q5 x8 v* A# ?
可能的方法4-PostgreSQL数组聚合器和GROUP BY
. a* D% ]4 D; Y$ |$ M% t尽管我相信这将 不会 工作,我已经包含了这个未经测试的选项,看看它是否可以改进 可 工作。
- q1 h# v7 x1 b2 w( h* I, v& mvar items = []Item{}sqlxdb.Select(&items,"SELECT i.id as item_id,array_agg(t.*) as tags FROM item AS i JOIN tag AS t ON t.item_id = i.id GROUP BY i.id")有时间的时候,我会试着在这里做一些实验。
4 x7 e2 y/ g. U- s) x' I4 o . B) |1 V! t, ]" P5 ^
解决方案:
6 B9 t! _: `$ \( G1 p& c: m8 O postgres中的sql:0 s' x9 Z8 v9 ^ f5 u2 K" x' ?
create schema temp;set search_path = temp;create table item( id INT generated by default as identity primary key);create table tag( id INT generated by default as identity primary key, name VARCHAR(160), item_id INT references item (id));create view item_tags asselect id, ( select array_to_json(array_agg(row_to_json(taglist.*))) as array_to_json from ( select tag.name,tag.id from tag where item_id = item.id ) taglist ) as tagsfrom item ;-- golang query this maybe select row_to_json(row)from ( select * from item_tags) row;然后golang查询这个SQL:% |! c. O+ V' Z2 z q9 ~0 k7 G$ x1 v
select row_to_json(row)from select * from item_tags) row;并解组结构:2 O$ V: m) h( z2 L6 C* H
优点:: t) j5 B+ u* S' w
[ol]postgres管理数据关系sql函数添加/更新数据。; a e { q! ~- z/ C2 [/ _
golang管理业务模型和逻辑。+ A- G! L; }! R! |+ J
[/ol]这是一个简单的方法。! M R8 l+ l+ p, E
。 |
|