Rust diesel orm查询

7

我是新手,对于rust和diesel orm都不太熟悉。我正在尝试在我的查询中执行以下操作:

  • 计数
  • 选择
  • 排序
  • 限制

但是我遇到了错误。
我正在使用postgres数据库。

我已经在查询上注释了确切的错误。
这是我的代码:

schema.rs

table! {
    employee (employee_id) {
        employee_id -> Int4,
        name -> Nullable<Text>,
        age -> Nullable<Int4>,
        address -> Nullable<Text>,
        email -> Nullable<Text>,
        dept_id -> Int4,
        salary -> Nullable<Numeric>,
        created_on -> Nullable<Timestamp>,
        created_by -> Nullable<Text>,
        modified_on -> Nullable<Timestamp>,
        modified_by -> Nullable<Text>,
        is_active -> Nullable<Bool>,
    }
}

models.rs

#![allow(unused)]
#![allow(clippy::all)]
use super::schema::employee;

use bigdecimal::BigDecimal;
use chrono::NaiveDateTime;

#[derive(Queryable, Debug, Identifiable)]
#[table_name = "employee"]
#[primary_key(employee_id)]
pub struct Employee {
    pub employee_id: i32,
    pub name: Option<String>,
    pub age: Option<i32>,
    pub address: Option<String>,
    pub email: Option<String>,
    pub dept_id: i32,
    pub salary: Option<BigDecimal>,
    pub created_on: Option<NaiveDateTime>,
    pub created_by: Option<String>,
    pub modified_on: Option<NaiveDateTime>,
    pub modified_by: Option<String>,
    pub is_active: Option<bool>,
}

cargo.toml

[dependencies]
diesel = { version = "1.4.5", features = ["postgres","chrono","numeric"] }
dotenv = "0.15.0"
chrono = { version = "0.4.19" , features = ["serde"] }
bigdecimal = { version = "0.1.0" }

main.rs

#[macro_use]
extern crate diesel;
extern crate bigdecimal;
extern crate chrono;
extern crate dotenv;

use crate::models::Employee;
use crate::models::Players;
use crate::schema::employee::dsl::*;

use diesel::{pg::PgConnection, prelude::*};
use dotenv::dotenv;
use std::env;

mod models;
mod schema;

fn main() {
    dotenv().ok();
    let data_url: String = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let connection: PgConnection =
        PgConnection::establish(&data_url).expect(&format!("Error connect to {}", data_url));

    //get all employees name
    //This is working fine
    let _employee: Vec<Employee> = employee
        .load::<Employee>(&connection)
        .expect("Error loading department");

    for emp in _employee {
        println!("{}", emp.name.unwrap_or_default());
    }


    //----------------------------------------------
    //get employees count
    /*
    Error: error[E0282]: type annotations needed
           ^^^^^^^^^^^^^^^ consider giving `total_employees` a type
    */
    let total_employees = employee.count().get_result(&connection).expect("Error");
    println!("{}", total_employees);


    //-----------------------------------------------
     //get all names
    /*
        Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not satisfied
         ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let all_names = employee.select(name).load::<String>(&connection)?;
    println!("{}", all_names);


    //----------------------------------------------
    //order name
    /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not          satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let ordered_names = employee
        .select(name)
        .order(name.desc())
        .load::<String>(&connection)?;
    println!("{}", ordered_names);


   //------------------------------------------------
   /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not     satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
     */
    let limited = employee
        .select(name)
        .order(employee_id)
        .limit(1)
        .load::<String>(&connection)?;
    println!("{}", limited);
}

我有什么遗漏吗? 有人能纠正我吗?
谢谢!

2个回答

10
首先:您的代码缺少关键信息,无法实际重现所描述的问题。如果不知道底层数据库模式的情况下,只能猜测其外观。对于我的答案,我将假设以下模式:
table! {
    employee(employee_id) {
        employee_id -> Integer,
        name -> Nullable<Text>,
        age -> Nullable<Integer>,
        address -> Nullable<Text>,
        email -> Nullable<Text>,
        dept_id -> Integer,
        salary -> Nullable<Numeric>,
        created_on -> Nullable<Timestamp>,
        created_by -> Nullable<Text>,
        modified_on -> Nullable<Timestamp>,
        modified_by -> Nullable<Text>,
        is_active -> Nullable<Bool>,
    }
}

现在作为一般规则:Diesel使用此定义作为事实依据,并只支持某些类型映射。如果您遇到编译错误,那么可能意味着以下某些事情出错了:

  • 您试图将查询结果映射到包含与返回列某些不兼容字段的结构体中
  • 您试图将查询结果映射到比您的查询返回的字段更多或更少的结构体中

回答您特定的错误消息:

    //----------------------------------------------
    //get employees count
    /*
    Error: error[E0282]: type annotations needed
           ^^^^^^^^^^^^^^^ consider giving `total_employees` a type
    */
    let total_employees = employee.count().get_result(&connection).expect("Error");
    println!("{}", total_employees);

Rustc在此需要知道total_employees的类型,因为get_result返回了一个泛型类型,而println则消耗了另一种泛型类型。Rustc需要确切地知道应使用哪种类型。现在,在这里,Diesel文档有些稀少,但Daniel Porteous中的错误消息表明该查询返回一个BigInt,它与此处文档记录的i64兼容。这意味着这个查询会起作用:
    let total_employees: i64 = employee.count().get_result(&connection).expect("Error");

你接下来的三个查询在本质上都无法编译,且出现了相同的错误信息:

    //-----------------------------------------------
     //get all names
    /*
        Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not satisfied
         ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let all_names = employee.select(name).load::<String>(&connection)?;
    println!("{}", all_names);


    //----------------------------------------------
    //order name
    /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not          satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
    */
    let ordered_names = employee
        .select(name)
        .order(name.desc())
        .load::<String>(&connection)?;
    println!("{}", ordered_names);


   //------------------------------------------------
   /*
    Error: error[E0277]: the trait bound `*const str: FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not     satisfied
    ^^^^ the trait `FromSql<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>` is not implemented for `*const str`
     */
    let limited = employee
        .select(name)
        .order(employee_id)
        .limit(1)
        .load::<String>(&connection)?;
    println!("{}", limited);

这些错误信息表明,您尝试将查询返回的字段映射到Rust端上不兼容的类型。在这种情况下,不能将一个非“NOT NULL”的Text字段映射为String,因为在这种情况下,如何表示NULL值是一个问题。 文档指出,您需要在Rust端上使用Option来包装可空类型。这意味着如果您在所有情况下将返回类型更改为Option<String>,则一切都将成功编译。

你说得对。我的模式与你上面提到的相同。我还编辑了问题,现在它有“schema.rs”。抱歉我错过了那个。 - Glenn singh
更改返回类型!!!你是不是想说我的其他查询应该像这样“let all_names: Option<String> = employee.select(name).load::<String>(&connection)?;”以及限制的查询应该像这样:let limited: Option<String> = employee .select(name) .order(employee_id) .limit(1) .load::<String>(&connection)?; 你是指这种方式吗? - Glenn singh
1
通过更改返回类型,我是指更改这些查询返回的类型。您已经通过使用 turbofish 语法在 .load 上设置了它们,因此只需将 .load :: <String>(&connection)? 更改为 .load :: <Option<String>>(&connection)? - weiznich
解释问题非常有帮助,谢谢@weiznich。 - Tolumide

0
let total_employees = employee.count().get_result(&connection).expect("Error");

对于这个问题,请尝试注释total_employees,就像这样:

let total_employees: u64 = employee.count().get_result(&connection).expect("Error");

这将有助于您继续进行。即使函数没有返回此类型,错误现在至少会告诉您它是什么类型。


我注意到在加载员工时,您使用了Turbofish,例如.load::<Employee>()。您对于count()也需要吗? - Daniel Porteous
它没起作用。我仍然得到一个错误“^^^^^^^^^^对于u64未实现FromSql<diesel :: sql_types :: BigInt,Pg>特性”。 - Glenn singh
这个答案是误导性的,因为 u64 不是 diesel 支持的类型(正如错误信息所告诉你的那样)。 - weiznich
答案有所帮助,因为现在问题的提问者知道他们需要使用BigInt。一般的建议是添加类型注释,以便编译器告诉您正在使用的类型。 - Daniel Porteous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接