Aller au contenu

ORM Processing (SeaORM)

Ce contenu n’est pas encore disponible dans votre langue.

Spring Batch RS integrates with SeaORM for type-safe ORM-based database operations. Use SeaORM’s powerful query builder with batch processing capabilities.

use spring_batch_rs::item::orm::{OrmItemReaderBuilder, OrmItemWriterBuilder};
use sea_orm::{Database, EntityTrait, QueryFilter};
// Read with SeaORM query
let query = products::Entity::find()
.filter(products::Column::Active.eq(true));
let reader = OrmItemReaderBuilder::new()
.connection(&db)
.query(query)
.page_size(100)
.build();
// Write active models directly
let writer = OrmItemWriterBuilder::<products::ActiveModel>::new()
.connection(&db)
.build();
  • Type-safe queries: SeaORM’s compile-time checked queries
  • Pagination: Efficient page-based reading
  • Direct entity writing: Write active models without mappers
  • All SeaORM databases: PostgreSQL, MySQL, SQLite, SQL Server
  • Async-to-sync bridge: Works with batch framework’s sync API

The orm_processing example uses SQLite in-memory (no external database required) and demonstrates:

  1. Read all products: Export to JSON with pagination
  2. Filtered queries: Query by category and stock status
  3. Complex filters: Price-based filtering
  4. Write entities: Insert new records from DTOs
  5. Verify writes: Read back and export new records
Terminal window
cargo run --example orm_processing --features orm,csv,json
MethodDescription
connection(&DatabaseConnection)Set database connection (required)
query(Select<E>)Set SeaORM select query (required)
page_size(u64)Set pagination size (optional)
build()Build the reader
MethodDescription
connection(&DatabaseConnection)Set database connection (required)
build()Build the writer

Use SeaORM’s derive macros to define entities:

use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
#[sea_orm(table_name = "products")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub category: String,
pub price: f64,
pub in_stock: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
use sea_orm::{EntityTrait, QueryFilter, QueryOrder};
let query = products::Entity::find()
.filter(products::Column::Category.eq("Electronics"))
.filter(products::Column::InStock.eq(true))
.order_by_asc(products::Column::Name);
let reader = OrmItemReaderBuilder::new()
.connection(&db)
.query(query)
.page_size(50)
.build();

Convert business DTOs to SeaORM active models:

use sea_orm::ActiveValue::Set;
struct DtoToActiveModelProcessor;
impl ItemProcessor<ProductDto, products::ActiveModel> for DtoToActiveModelProcessor {
fn process(&self, item: &ProductDto) -> Result<products::ActiveModel, BatchError> {
Ok(products::ActiveModel {
id: Set(item.id),
name: Set(item.name.clone()),
category: Set(item.category.clone()),
price: Set(item.price),
in_stock: Set(item.in_stock),
})
}
}
let step = StepBuilder::new("import-products")
.chunk::<ProductDto, products::ActiveModel>(50)
.reader(&dto_reader)
.processor(&DtoToActiveModelProcessor)
.writer(&orm_writer)
.build();
// Query with related entities
let query = orders::Entity::find()
.find_also_related(customers::Entity)
.filter(orders::Column::Status.eq("pending"));
// Convert SeaORM Model to CSV-friendly struct
struct ModelToCsvProcessor;
impl ItemProcessor<products::Model, ProductCsv> for ModelToCsvProcessor {
fn process(&self, item: &products::Model) -> Result<ProductCsv, BatchError> {
Ok(ProductCsv {
id: item.id,
name: item.name.clone(),
price: item.price,
})
}
}
let step = StepBuilder::new("export-csv")
.chunk::<products::Model, ProductCsv>(100)
.reader(&orm_reader)
.processor(&ModelToCsvProcessor)
.writer(&csv_writer)
.build();
use sea_orm::Database;
#[tokio::main]
async fn main() -> Result<(), BatchError> {
// SQLite in-memory
let db = Database::connect("sqlite::memory:").await?;
// PostgreSQL
// let db = Database::connect("postgresql://user:pass@localhost/db").await?;
// MySQL
// let db = Database::connect("mysql://user:pass@localhost/db").await?;
// Create tables...
db.execute_unprepared("CREATE TABLE products (...)").await?;
// Use with readers/writers
}

For reading from in-memory collections:

struct InMemoryReader<T> {
items: RefCell<VecDeque<T>>,
}
impl<T: Clone> InMemoryReader<T> {
fn new(items: Vec<T>) -> Self {
Self { items: RefCell::new(items.into()) }
}
}
impl<T: Clone> ItemReader<T> for InMemoryReader<T> {
fn read(&self) -> Result<Option<T>, BatchError> {
Ok(self.items.borrow_mut().pop_front())
}
}