为柴油模型定义结构时出现错误未定义类型或模块

Posted

技术标签:

【中文标题】为柴油模型定义结构时出现错误未定义类型或模块【英文标题】:Getting error undefined type or module when defining struct for diesel models 【发布时间】:2020-06-27 10:11:36 【问题描述】:

我无法让柴油在 Rust 上运行。这个项目的背景是一个使用 postgres 作为服务器来保存分数和使用柴油访问 postgres 的分数统计系统。当我在 models.rs 中定义一个结构(名为 Score)时,我得到了这个错误:

error[E0433]: failed to resolve: use of undeclared type or module `scores`
 --> src/models.rs:7:16
  |
7 | #[table_name = "scores"]
  |                ^^^^^^^^ use of undeclared type or module `scores`

schema.rs 的内容是:

table! 
    scores (name) 
        name -> Varchar,
        points -> Nullable<Int4>,
        subject -> Nullable<Varchar>,
    

这是我的models.rs:

#[macro_use]
use diesel::*;
use diesel::sql_types::*;
use crate::schema::scores::*;

#[derive(Queryable, Insertable, QueryableByName)]
#[table_name = "scores"]
pub struct Score 
    #[sql_type = "Varchar"]
    name: String,
    #[sql_type = "Integer"]
    points: Option<i32>,
    #[sql_type = "Varchar"]
    subject: Option<String>,

我正在尝试使用 add_entry.rs 向其中添加条目:

use super::models::Score;
use diesel::pg::PgConnection;
use crate::schema::*;

pub fn create_score(conn: PgConnection, name: String, score: i32, subject: String) -> () 
    let new_score = Score 
        name: name,
        points: Some(score),
        subject: Some(subject),
    ;   

    let ins = diesel::insert_into(scores::table)
        .values(new_score)
        .execute(&conn);

在 main.rs 中,我有:

#[macro_use] extern crate diesel;
mod add_entry;
mod connect;
mod models;
mod schema;
use diesel::dsl::sql_query;

fn main() 
    let conn = connect::connect();
    let name = String::from("name");
    let subject = String::from("subject");
    add_entry::create_score(conn, name.clone(), 75, subject.clone());
    //random data
    list_score();


fn list_score() 
    let connection = connect::connect();
    let result = sql_query("SELECT * FROM scores");
    println!(":#?", result);

在 connect.rs(连接服务器)我有:

use dotenv::dotenv;
use diesel::pg::PgConnection;
use diesel::prelude::*;
use std::env;

pub fn connect() -> PgConnection 
     dotenv().ok();
     let database_url = env::var("DATABASE_URL")
         .expect("Cannot get DB URL.");
     PgConnection::establish(&database_url)
         .expect(&format!("Error connecting to ", database_url));

我的 Cargo.toml 的依赖部分的内容是

dotenv = "0.9.0" 
diesel =  git = "https://github.com/diesel-rs/diesel", features = ["postgres"] 

为了得到这个错误,我运行 diesel setup 来设置一切,diesel migration rundiesel migration redodiesel migration run 再次,最后是 cargo build

我的完整代码可以在这个repository中找到。

我应该怎么做才能消除这个错误? 谢谢。

【问题讨论】:

你如何编译你的代码?你输入了什么命令,你的Cargo.toml的内容是什么? 我使用cargo build编译,我的Cargo.toml的内容是dotenv = "0.9.0" diesel = git = "https://github.com/diesel-rs/diesel", features = ["postgres"] 我发现导致此问题的行可能是#[derive(Queryable, Insertable)],但我不知道该如何解决。我要求这条线能够查询并插入其中。那我该怎么办? 您是否按照diesel.rs/guides/getting-started 中的说明进行操作? IE。你通常需要运行diesel setup,创建数据库,为具有相应名称的表编写一些迁移等。你应该调用你的类型Score,因此表名被推断为scores。您可能也不想使用i8,因为没有对应的 Postgres 数据类型。 To make Stack Overflow a useful resource for future visitors beyond the context of your repository,请edit 您的问题在问题本身中添加minimal reproducible example,除了指向您的存储库的链接。 【参考方案1】:

简短回答:您需要导入 use crate::schema::scores; 而不是 use crate::schema::scores::*;

更长的解释:

Diesel 的table! 宏生成一个相当复杂的模块结构,包含多种类型。此外,这些类型是从不同位置重新导出的,例如 dsl 模块。派生需要知道crate::schema::your_table::table 类型和每列的所有类型(所以crate::schema::your_table::column_a,...)。由于它无法访问整个模块并且不知道范围内的类型,因此柴油需要以某种方式推断该类型。最简单的方法是从某个地方获取模块名称。这是通过#[table_name = "your_table"] 属性完成的,该属性假定模块your_table 在包含表和列的相应类型的范围内。

有关更多详细信息,请查看以下文档:

Insert Guide Documentation for table! macro

【讨论】:

【参考方案2】:

如果您的架构包含可为空的字段,您需要在 rust 端为此类字段使用 Option&lt;T&gt;

#[macro_use]
use diesel::*;

use crate::schema::scores;

#[derive(Queryable, Insertable)]
//#[table_name = "scores"]
pub struct Score 
    //#[sql_type = "Varchar"]
    pub name: String,
    //#[sql_type = "Integer"]
    pub points: Option<i32>,
    //#[sql_type = "Varchar"]
    pub subject: Option<String>,
    //#[sql_type = "Varchar"]
    pub date: Option<String>,

并且在使用diesel::insert_into时记得导入schema::scores

add_entry.rs:

use super::models::Score;
use crate::schema::scores;
use diesel::pg::PgConnection;
use diesel::prelude::*;

pub fn create_score(
    conn: PgConnection,
    name: String,
    score: i32,
    subject: String,
    date: String,
) -> () 
    let new_score = Score 
        name: name,
        points: Some(score),
        subject: Some(subject),
        date: Some(date),
    ;

    let ins = diesel::insert_into(scores::table)
        .values(new_score)
        .execute(&conn);

如果您解决了使用移动值到 main.rs 时出现的问题,您现在可以编译您的项目。

add_entry::create_score(
    connection,
    option.clone(),
    scores,
    subject.clone(),
    date.clone(),
);

【讨论】:

我会试试这个,稍后再报告。谢谢 即使我的models.rs 的内容与您写的内容完全相同,我仍然会收到相同的错误。我已经将表中scores 列的名称、迁移和架构更改为points 可能是因为我尝试使用 SQL 查询而不是柴油指南中提供的查询?我尝试实现QueryableByName 来做到这一点,而这又需要#[table_name = "scores"]。这导致错误打开#[table_name = "scores"] 不幸的是,这仍然没有改变任何东西。能否也请教一下为什么我似乎无法使用正常的代码从数据库中查询。要查询,我使用此代码:let average = sql_query("SELECT AVG(score) FROM scores");。这可能与问题有关吗?由于某些原因,例如here,我什至不能在此代码上使用.load() @StephenTaharuddin 我的随机猜测是你省略了mod schemause schema::* 或类似的东西。如果您想要的不仅仅是随机猜测,请提供一个最小的可重现示例。 :)

以上是关于为柴油模型定义结构时出现错误未定义类型或模块的主要内容,如果未能解决你的问题,请参考以下文章

运行代码时出现用户定义类型未定义错误

未捕获的类型错误:无法读取未定义的属性“ui”。选择croparea时出现JQuery JCrop问题

构建 Vue 项目时出现错误“无法安装组件:未定义模板或渲染函数”

模拟调用“upvote”的效果时出现异常。类型错误:未定义不是函数

在 Node.js 应用程序中使用 Webpack 时出现类型错误“无法读取未定义的属性‘jquery’”

未捕获的类型错误:无法读取未定义的属性(读取“替换”)