1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ent】複合主キーで `edge schema primary key can only be defined on "id" or ... in the same order` が発生した場合の対処法

Posted at

複合主キー関連のその他のエラーはこちら

TL; DR

複合主キーの field.ID の引数の順序を逆にすれば解消する

func (StudentCourse) Annotations() []schema.Annotation {
	return []schema.Annotation{
		// 複合主キー
		field.ID("student_id", "course_id"),
	}
}

エラーの再現

まずはスキーマを作成します。今回は以下のテーブルを考えます。

-- 講義受講者の成績
CREATE TABLE StudentCourses
(student_id integer NOT NULL.
 course_id integer NOT NULL,
 grade integer NOT NULL
PRIMARY KEY (student_id, course_id));

-- 学生一覧
CREATE TABLE Students
(id integer NOT NULL,
 name varchar(255) NOT NULL
PRIMARY KEY (id));

-- 講義一覧
CREATE TABLE Courses
(id integer NOT NULL,
 name varchar(255) NOT NULL
PRIMARY KEY (id));

複合主キーと関連テーブルを以下のように定義します。

// StudentCourse holds the schema definition for the StudentCourse entity.
type StudentCourse struct {
	ent.Schema
}

func (StudentCourse) Annotations() []schema.Annotation {
	return []schema.Annotation{
		// 複合主キーを指定(デフォルトでは `id` というフィールドが主キーとなる)
		field.ID("course_id", "student_id"),
	}
}

// Fields of the StudentCourse.
func (StudentCourse) Fields() []ent.Field {
	return []ent.Field{
		field.Int("student_id"),
		field.Int("course_id"),
		field.Int("grade"),
	}
}

// Edges of the StudentCourse.
func (StudentCourse) Edges() []ent.Edge {
	return []ent.Edge{
		edge.To("student", Student.Type).
			Unique().
			Required().
			Field("student_id"),
		edge.To("course", Course.Type).
			Unique().
			Required().
			Field("course_id"),
	}
}
// ...
// Fields of the Student.
func (Student) Fields() []ent.Field {
	return []ent.Field{
		field.Int("id"),
		field.String("name"),
	}
}

// Edges of the Student.
func (Student) Edges() []ent.Edge {
	return []ent.Edge{
		edge.To("registered_courses", Course.Type).
			Through("student_courses", StudentCourse.Type),
	}
}
// ...
// Fields of the Course.
func (Course) Fields() []ent.Field {
	return []ent.Field{
		field.Int("id"),
		field.String("name"),
	}
}

// Edges of the Course.
func (Course) Edges() []ent.Edge {
	// 逆向きの関連をこちらにも指定
	return []ent.Edge{
		edge.From("students", Student.Type).
			Ref("registered_courses").
			Through("student_courses", StudentCourse.Type),
	}
}

Edge() を定義している理由については以下の記事をご覧ください。

この状態でソースコードを自動生成使用とすると以下のエラーが発生します。

$ go generate ./ent
entc/gen: resolving edges: edge schema primary key can only be defined on "id" or ("student_id", "course_id") in the same order
exit status 1
ent/generate.go:3: running "go": exit status 1

対処法

エラーメッセージにもあるように、複合主キーを ("student_id", "course_id") の順序で定義することで解消します。

func (StudentCourse) Annotations() []schema.Annotation {
	return []schema.Annotation{
		// 複合主キーを指定(デフォルトでは `id` というフィールドが主キーとなる)
-		field.ID("course_id", "student_id"),
+		field.ID("student_id", "course_id"),
	}
}

これは、複合主キーとedge schemaを対応付ける際に順序依存で比較を行っているためです。

			// Edge schema contains a composite primary key, and it was not resolved in previous iterations.
			if ant := fieldAnnotate(edgeT.Annotations); ant != nil && len(ant.ID) > 0 && len(edgeT.EdgeSchema.ID) == 0 {
				r1, r2 := e.Rel.Columns[0], e.Rel.Columns[1]
				if len(ant.ID) != 2 || ant.ID[0] != r1 || ant.ID[1] != r2 {
					return fmt.Errorf(`edge schema primary key can only be defined on "id" or (%q, %q) in the same order`, r1, r2)
				}
				// ...
			}

field.ID の引数は

  • edge.To で指定したもの
  • edge.From で指定したもの

の順に指定する必要があります。

そのため、edge.To で指定した student に対応する student_id が先行することで解消されます。

entc/gen/graph.go
// Edges of the StudentCourse.
func (StudentCourse) Edges() []ent.Edge {
	return []ent.Edge{
		edge.To("student", Student.Type).
			Unique().
			Required().
			Field("student_id"),
		edge.To("course", Course.Type).
			Unique().
			Required().
			Field("course_id"),
	}
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?