ent / ent/ent

Potential Issue with Duplicate UUIDs in Many-to-Many Relationships

Open
#3,763 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
17.2k
Forks
1k
PR merge metrics
No merged PRs in 30d

Description

Hello, First of all, I would like to express my appreciation for the excellent work on the ent library 🙌 ✨

---

It has been very beneficial in my project. I've encountered a potential issue that I wanted to bring to your attention.
Here is the sql and go code I'm using:

.sql

スクリーンショット 2023-09-27 0 55 45

```sql
CREATE TABLE "public"."channel" (
"channel_id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"alphabet_index" varchar DEFAULT ''::character varying,
"created_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"fk_parent_channel_id" uuid,
PRIMARY KEY ("channel_id")
);

CREATE TABLE "public"."channel_topic" (
"channel_topic_id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"created_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"channel_id" uuid NOT NULL,
"topic_id" uuid NOT NULL,
PRIMARY KEY ("channel_topic_id")
);

CREATE TABLE "public"."topic" (
"topic_id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"created_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
"fk_topic_type_id" varchar NOT NULL,
PRIMARY KEY ("topic_id")
);

ALTER TABLE "public"."channel" ADD FOREIGN KEY ("fk_parent_channel_id") REFERENCES "public"."channel"("channel_id") ON DELETE SET NULL;
ALTER TABLE "public"."channel_topic" ADD FOREIGN KEY ("channel_id") REFERENCES "public"."channel"("channel_id");
ALTER TABLE "public"."channel_topic" ADD FOREIGN KEY ("topic_id") REFERENCES "public"."topic"("topic_id");
ALTER TABLE "public"."topic" ADD FOREIGN KEY ("fk_topic_type_id") REFERENCES "public"."topic_type"("topic_type_id");

```

.go

```go
func (db *db) create(ctx context.Context, record *record) (*ent.Channel, error) {
tx, _ := db.client.Debug().Tx(ctx)

topics, err := tx.
Topic.
Query().
Where(topic.IDIn(record.topicIDs...)).
All(ctx)

if err != nil {
_ = tx.Rollback()

return nil, err
}

channel, err := tx.
Channel.
Create().
SetAlphabetIndex("").
SetID(db.channelID(ctx, record.topicIDs...)).
AddTopics(topics...). // this is.
SetParentID(record.parentID).
Save(ctx)

if err != nil {
_ = tx.Rollback()

return nil, err
}

_ = tx.Commit()

return channel, nil
}
```

The problem arises when attempting to create a new channel and associate it with multiple topics.
The channel_topic table entries should each have a unique channel_topic_id generated by default via uuid_generate_v4().

However, when adding multiple topics to a channel using the `AddTopics(topics...)` method,
the same channel_topic_id is being used for all the entries, causing a below error 🤔.

```
add m2m edge for table channel_topic: pq: duplicate key value violates unique constraint \"channel_topic_pkey\""
```

I had to work around this issue by adding each topic individually in a loop, like this: (It's work 🙌)

```go
for _, t := range topics {
err = channel.Update().AddTopics(t).Exec(ctx)
if err != nil {
_ = tx.Rollback()
return nil, err
}
}
```

This ensures that each channel_topic entry gets a unique ID,
but it seems like something that should be handled internally by the ent library.
Could you please look into this? Thank you for your attention to this matter. 🙌

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the failure with the shown PostgreSQL schema and the Go transaction using Channel.Create().AddTopics(topics...). Inspect the many-to-many insertion path for channel_topic and compare it with adding topics individually. Done means bulk AddTopics creates a distinct channel_topic_id for every association without a duplicate-key error.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.