本章将讨论多对多:一篇文章可以有多个标签,同样的,一个标签可以对应多篇文章。
多对多关系,在数据库中需要借助第三张表来维护。
数据表及示例数据
我们需要创建两个表,并插入一些示例数据:
表 | 说明 |
---|---|
tags | 标签 |
article_tags | 文章和标签的对应关系 |
实体
多对多中间实体的定义
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "article_tags")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
pub article_id: i32,
pub tag_id: i32,
}
#[derive(Debug, Clone, Copy, EnumIter)]
pub enum Relation {
Article,
Tag,
}
impl RelationTrait for Relation {
fn def(&self) -> sea_orm::RelationDef {
match self {
Self::Article => Entity::belongs_to(super::article::Entity)
.from(Column::ArticleId)
.to(super::article::Column::Id)
.into(),
Self::Tag => Entity::belongs_to(super::tag::Entity)
.from(Column::TagId)
.to(super::tag::Column::Id)
.into(),
}
}
}
impl ActiveModelBehavior for ActiveModel {}
我们在中间实体中定义了两个关系:
Relation::Artice
:通过article_id = articles.id
与文章建立关系Relation:Tag
:通过tag_id = tags.id
与标签建立关系
两个关系都是通过 belongs_to()
定义的。
标签实体的定义
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "tags")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
pub name: String,
}
#[derive(Debug, Clone, Copy, EnumIter)]
pub enum Relation {}
impl RelationTrait for Relation {
fn def(&self) -> sea_orm::RelationDef {
panic!()
}
}
impl Related<super::article::Entity> for Entity {
fn to()->RelationDef {
super::article_tag::Relation::Article.def()
}
fn via() -> Option<RelationDef> {
Some(super::article_tag::Relation::Tag.def().rev())
}
}
impl ActiveModelBehavior for ActiveModel {}
我们并没有给标签实体定义关系,而是通过 Related<super::article::Entity>
告诉 SeaORM如何去找所需要的文章实体。
Related::to()
Related::to()
:某个实体是否与另一个实体相关。
tag::Entity::Related<super::article::Entity>::to()
表示, tag::Entity
里的article::Entity
是通过 article_tag::Relation::Article.def()
获得的。完整的路径是:Tag -> ArticleTag -> Article
Related::via()
Related::via()
:某个实体是否通过另一个实体关联。
tag::Entity::Related<super::article::Entity>::via()
的结果是,原始的ArticleTag -> Tag
将变成 Tag -> ArticleTag
。
to()
和via()
我也不知道怎么描述,或许你的理解能力比我强,欢迎分享。理解不了也没关系,照抄就好了。——通过 SeaORM 生成的 SQL 语句来验证是否正确、是否合理。
文章实体中定义和标签的关系
给src/entity/article.rs添加和标签的关系:
impl Related<super::tag::Entity> for Entity {
fn to() -> RelationDef {
super::article_tag::Relation::Tag.def()
}
fn via() -> Option<RelationDef> {
Some(super::article_tag::Relation::Article.def().rev())
}
}
显示带标签的文章列表
多对多关系定义好之后,可以在任意一方来查询。比如本例的通过文章列表来同时显示标签:
如果要通过标签来查询关联的文章,只需要:
本章代码位于07/多对多分支