在 Diesel 中引用相同 table 的多个外键
Multiple foreign keys referencing same table in Diesel
我正在尝试创建一个引用相同 table 两次的结构。这样做的目的是创建一种类别层次结构。这是我为跟随 tables:
而尝试做的事情
create table product_category_rollup(
id serial primary key,
upper_category_id integer not null,
lower_category_id integer not null,
foreign key (upper_category_id) references product_category(id),
foreign key (lower_category_id) references product_category(id)
);
create table product_category(
id serial primary key,
name varchar unique not null
);
我正在尝试创建匹配的结构:
#[derive(Identifiable, Queryable)]
#[table_name = "product_category"]
pub struct ProductCategory {
id: i32,
name: String,
}
#[derive(Queryable, Identifiable, Associations)]
#[belongs_to(ProductCategory, foreign_key="upper_category_id")]
#[belongs_to(ProductCategory, foreign_key="lower_category_id")]
#[table_name = "product_category_rollup"]
pub struct ProductCategoryRollup {
id: i32,
upper_category_id: i32,
lower_category_id: i32,
}
我收到一条错误消息:
error[E0119]: conflicting implementations of trait `diesel::associations::BelongsTo<entities::ProductCategory>` for type `entities::ProductCategoryRollup`:
--> src/entities.rs:29:35
|
29 | #[derive(Queryable, Identifiable, Associations)]
| ^^^^^^^^^^^^
| |
| first implementation here
| conflicting implementation for `entities::ProductCategoryRollup`
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
让多个外键引用同一个 table 的正确方法是什么?这是 Diesel 中尚未解决的一些固有限制吗?
BelongsTo
特征定义是:
pub trait BelongsTo<Parent> {
type ForeignKey: Hash + Eq;
type ForeignKeyColumn: Column;
fn foreign_key(&self) -> Option<&Self::ForeignKey>;
fn foreign_key_column() -> Self::ForeignKeyColumn;
}
由于 ForeignKey
(和 ForeignKeyColumn
)是关联类型,而不是泛型参数,给定的 Child
只能有一个 BelongsTo<Parent>
的实现。
总的来说,BelongsTo
似乎相当有限;请注意,它也仅限于单列。
所以我一直在研究和研究 Diesel,正如上面的答案中已经指出的那样,这个问题的出现是由于 BelongsTo<Parent>
特征的定义方式。
一种避免这种情况的方法是执行以下操作:
// This trait contains the behavior common to all types
// representing the product category
trait ProductCategory{
fn new(id: i32, name: String) -> Self;
}
#[derive(Identifiable)]
#[table_name = "product_category"]
pub struct RawProductCategory {
id: i32,
name: String,
}
#[derive(Identifiable)]
#[table_name = "product_category"]
pub struct UpperProductCategory {
pub id: i32,
pub name: String,
}
#[derive(Identifiable)]
#[table_name = "product_category"]
pub struct LowerProductCategory {
pub id: i32,
pub name: String
}
impl ProductCategory for RawProductCategory {
fn new(id: i32, name: String) -> Self {
RawProductCategory {
id,
name
}
}
}
impl ProductCategory for UpperProductCategory {
fn new(id: i32, name: String) -> Self {
UpperProductCategory {
id,
name
}
}
}
impl ProductCategory for LowerProductCategory {
fn new(id: i32, name: String) -> Self {
LowerProductCategory {
id,
name
}
}
}
impl Queryable<product_category::SqlType, diesel::pg::Pg> for RawProductCategory {
type Row = (i32, String);
fn build(row: Self::Row) -> Self {
ProductCategory::new(row.0, row.1)
}
}
impl Queryable<product_category::SqlType, diesel::pg::Pg> for UpperProductCategory {
type Row = (i32, String);
fn build(row: Self::Row) -> Self {
ProductCategory::new(row.0, row.1)
}
}
impl Queryable<product_category::SqlType, diesel::pg::Pg> for LowerProductCategory {
type Row = (i32, String);
fn build(row: Self::Row) -> Self {
ProductCategory::new(row.0, row.1)
}
}
现在我注意到我在 Queryable 的实现方面有相当大的代码重复,但我不想通过引入另一个包含实现 ProductCategory
特征的单个字段的结构来减少它.
现在有趣的部分来了。我已经注意到为什么会出现这种情况,并已打开 issue in diesel Github repository。如果这个问题得到解决,我会相应地更新这个答案,以展示实现相同目标的更好方法。
我正在尝试创建一个引用相同 table 两次的结构。这样做的目的是创建一种类别层次结构。这是我为跟随 tables:
而尝试做的事情create table product_category_rollup(
id serial primary key,
upper_category_id integer not null,
lower_category_id integer not null,
foreign key (upper_category_id) references product_category(id),
foreign key (lower_category_id) references product_category(id)
);
create table product_category(
id serial primary key,
name varchar unique not null
);
我正在尝试创建匹配的结构:
#[derive(Identifiable, Queryable)]
#[table_name = "product_category"]
pub struct ProductCategory {
id: i32,
name: String,
}
#[derive(Queryable, Identifiable, Associations)]
#[belongs_to(ProductCategory, foreign_key="upper_category_id")]
#[belongs_to(ProductCategory, foreign_key="lower_category_id")]
#[table_name = "product_category_rollup"]
pub struct ProductCategoryRollup {
id: i32,
upper_category_id: i32,
lower_category_id: i32,
}
我收到一条错误消息:
error[E0119]: conflicting implementations of trait `diesel::associations::BelongsTo<entities::ProductCategory>` for type `entities::ProductCategoryRollup`:
--> src/entities.rs:29:35
|
29 | #[derive(Queryable, Identifiable, Associations)]
| ^^^^^^^^^^^^
| |
| first implementation here
| conflicting implementation for `entities::ProductCategoryRollup`
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
让多个外键引用同一个 table 的正确方法是什么?这是 Diesel 中尚未解决的一些固有限制吗?
BelongsTo
特征定义是:
pub trait BelongsTo<Parent> {
type ForeignKey: Hash + Eq;
type ForeignKeyColumn: Column;
fn foreign_key(&self) -> Option<&Self::ForeignKey>;
fn foreign_key_column() -> Self::ForeignKeyColumn;
}
由于 ForeignKey
(和 ForeignKeyColumn
)是关联类型,而不是泛型参数,给定的 Child
只能有一个 BelongsTo<Parent>
的实现。
总的来说,BelongsTo
似乎相当有限;请注意,它也仅限于单列。
所以我一直在研究和研究 Diesel,正如上面的答案中已经指出的那样,这个问题的出现是由于 BelongsTo<Parent>
特征的定义方式。
一种避免这种情况的方法是执行以下操作:
// This trait contains the behavior common to all types
// representing the product category
trait ProductCategory{
fn new(id: i32, name: String) -> Self;
}
#[derive(Identifiable)]
#[table_name = "product_category"]
pub struct RawProductCategory {
id: i32,
name: String,
}
#[derive(Identifiable)]
#[table_name = "product_category"]
pub struct UpperProductCategory {
pub id: i32,
pub name: String,
}
#[derive(Identifiable)]
#[table_name = "product_category"]
pub struct LowerProductCategory {
pub id: i32,
pub name: String
}
impl ProductCategory for RawProductCategory {
fn new(id: i32, name: String) -> Self {
RawProductCategory {
id,
name
}
}
}
impl ProductCategory for UpperProductCategory {
fn new(id: i32, name: String) -> Self {
UpperProductCategory {
id,
name
}
}
}
impl ProductCategory for LowerProductCategory {
fn new(id: i32, name: String) -> Self {
LowerProductCategory {
id,
name
}
}
}
impl Queryable<product_category::SqlType, diesel::pg::Pg> for RawProductCategory {
type Row = (i32, String);
fn build(row: Self::Row) -> Self {
ProductCategory::new(row.0, row.1)
}
}
impl Queryable<product_category::SqlType, diesel::pg::Pg> for UpperProductCategory {
type Row = (i32, String);
fn build(row: Self::Row) -> Self {
ProductCategory::new(row.0, row.1)
}
}
impl Queryable<product_category::SqlType, diesel::pg::Pg> for LowerProductCategory {
type Row = (i32, String);
fn build(row: Self::Row) -> Self {
ProductCategory::new(row.0, row.1)
}
}
现在我注意到我在 Queryable 的实现方面有相当大的代码重复,但我不想通过引入另一个包含实现 ProductCategory
特征的单个字段的结构来减少它.
现在有趣的部分来了。我已经注意到为什么会出现这种情况,并已打开 issue in diesel Github repository。如果这个问题得到解决,我会相应地更新这个答案,以展示实现相同目标的更好方法。