Skip to main content
Version: 0.12.x

Chained Relations

The Related trait is a representation of the arrows (1-1, 1-N, M-N) we draw on Entity Relationship Diagrams. A Linked is composed of a chain of relations, and is useful when:

  1. there exist multiple join paths between a pair of entities
  2. joining across multiple entities in a relational query

Take this as a simple example, where we join cake and filling via an intermediate cake_filling table.

entity/links.rs
pub struct CakeToFilling;

impl Linked for CakeToFilling {
type FromEntity = cake::Entity;

type ToEntity = filling::Entity;

fn link(&self) -> Vec<RelationDef> {
vec![
cake_filling::Relation::Cake.def().rev(),
cake_filling::Relation::Filling.def(),
]
}
}

Alternatively, the RelationDef can be defined on the fly, where the following is equivalent to the above:

pub struct CakeToFilling;

impl Linked for CakeToFilling {
type FromEntity = cake::Entity;

type ToEntity = filling::Entity;

fn link(&self) -> Vec<RelationDef> {
vec![
cake_filling::Relation::Cake.def().rev(),
cake_filling::Entity::belongs_to(filling::Entity)
.from(cake_filling::Column::FillingId)
.to(filling::Column::Id)
.into(),
]
}
}

Lazy Loading

Find fillings that can be filled into a cake with the find_linked method.

let cake_model = cake::Model {
id: 12,
name: "".to_owned(),
};

assert_eq!(
cake_model
.find_linked(cake::CakeToFilling)
.build(DbBackend::MySql)
.to_string(),
[
"SELECT `filling`.`id`, `filling`.`name`, `filling`.`vendor_id`",
"FROM `filling`",
"INNER JOIN `cake_filling` AS `r0` ON `r0`.`filling_id` = `filling`.`id`",
"INNER JOIN `cake` AS `r1` ON `r1`.`id` = `r0`.`cake_id`",
"WHERE `r1`.`id` = 12",
]
.join(" ")
);

Eager Loading

find_also_linked is a dual of find_also_related; find_with_linked is a dual of find_with_related; :

assert_eq!(
cake::Entity::find()
.find_also_linked(links::CakeToFilling)
.build(DbBackend::MySql)
.to_string(),
[
r#"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,"#,
r#"`r1`.`id` AS `B_id`, `r1`.`name` AS `B_name`, `r1`.`vendor_id` AS `B_vendor_id`"#,
r#"FROM `cake`"#,
r#"LEFT JOIN `cake_filling` AS `r0` ON `cake`.`id` = `r0`.`cake_id`"#,
r#"LEFT JOIN `filling` AS `r1` ON `r0`.`filling_id` = `r1`.`id`"#,
]
.join(" ")
);