首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么是最好的方式存储一个枚举在一个数据库中的rusqlite?

什么是最好的方式存储一个枚举在一个数据库中的rusqlite?
EN

Stack Overflow用户
提问于 2022-07-21 15:15:28
回答 1查看 139关注 0票数 0

如果我有一个简单的结构,其中一个属性包含一个简单的枚举,那么如何最好地在rusqlite数据库中存储这个结构的示例及其枚举呢?类似于:

代码语言:javascript
复制
use rusqlite::{params, Connection, Result};

enum Sex{
    Unknown,
    Male,
    Female,
}

struct Person{
    name: String,
    sex: Sex
}

fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;

    conn.execute(
        "CREATE TABLE  people(
            name TEXT NOT NULL,
            sex TEXT NOT NULL
        )",
        (), // empty list of parameters.
    )?;


    let person_01 = Person{
        name: String::from("Adam"),
        sex: Sex::Male
    };

    conn.execute(
        "INSERT INTO people (name, sex) VALUES (?1, ?2)",
        (&person_01.name, &person_01.sex),
    )?;

    Ok(())
}

问题是sqlite只允许受限制类型的数据(NULL、整型、实值、文本),试图在这里使用文本进行枚举会产生以下错误:

代码语言:javascript
复制
error[E0277]: the trait bound `Sex: ToSql` is not satisfied
   --> src/main.rs:33:9
    |
31  |     conn.execute(
    |          ------- required by a bound introduced by this call
32  |         "INSERT INTO tasklist (name, sex) VALUES (?1, ?2)",
33  |         (&person_01.name, &person_01.sex),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToSql` is not implemented for `Sex`

这个错误是有意义的,但是实现这个错误的最好方法是什么呢?把enum投给int?我读过这里,这是“消除了值总是表示枚举的变体的保证”,我同意这一点。把绳子配起来会更好。

我尝试使用女贞来完成这项工作,它允许我将to_str & from_str添加到枚举中,允许将其添加到数据库中,如下所示:

代码语言:javascript
复制
#[derive(strum_macros::Display, strum_macros::EnumString, Debug)]
enum Sex{
    Unknown,
    Male,
    Female,
}

...

    conn.execute(
        "INSERT INTO people (name, sex) VALUES (?1, ?2)",
        (&person_01.name, &person_01.sex.to_string())
    )?;

并像这样检索到:

代码语言:javascript
复制
    let mut stmt = conn.prepare("SELECT name, sex FROM people")?;
    let person_itr = stmt.query_map([], |row|{
        Ok(
            Person{
                name: row.get(0)?,
                sex: Sex::from_str(String::as_str(&row.get(1)?)).unwrap(),
            }
        )
    });

但这感觉很混乱。有更好的方法吗?

我见过这里人员手动为枚举实现FromSqlRow,但是有更好(更快)的方法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-21 17:36:18

正确的处理方法是直接在枚举上实现ToSqlFromSql。这将使它的使用更符合人体工程学,而且可能更有效率,因为您不必首先转换为带有分配的类型,比如String

它还意味着对字符串的转换不会“影响”与数据库的每一次交互;转换将自动进行。因此,尽管有更多的样板,但每次您将这种类型与数据库一起使用时,它都会得到回报。

代码语言:javascript
复制
impl ToSql for Sex {
    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
        Ok(self.to_string().into())
    }
}

impl FromSql for Sex {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str()?.parse()
            .map_err(|e| FromSqlError::Other(Box::new(e)))
    }
}

现在,您可以在转换为Person时执行此操作。

代码语言:javascript
复制
sex: row.get(1)?,

请注意,FromSqlRow是postgres客户端特有的一个特征;rusqlite没有这样的特性。如果您愿意,可以在Person上创建一个工厂方法,该方法是从一个Row构造的。那随你的便。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73068721

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档