You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法理解Fetcher.rel逻辑,附组织与事件Scala案例类定义

Understanding Fetcher.rel with Your Scala Domain Models

Got it, let's break down how to work with Fetcher.rel using your Organization/Event relationship. First, let's clarify what Fetcher.rel does at its core: it's a tool to define batch-fetching logic for related entities, solving the dreaded N+1 query problem by grouping all required related entity IDs and fetching them in one go instead of querying individually.

I'll use examples aligned with common Scala libraries (like ZIO Query, where Fetcher is widely used) but the core logic translates to any framework with similar fetcher abstractions.


1. First: Define Base Fetchers for Individual Entities

Before creating relationships, you need basic fetchers that can retrieve single entities by their IDs in bulk. These are the building blocks for Fetcher.rel.

import zio._
import zio.query._
import java.time.LocalDateTime

// Your existing case classes
case class OrganizationId(value: Long) extends AnyVal
case class Organization(id: OrganizationId, name: String, iban: Option[String], bic: Option[String], updatedAt: LocalDateTime, insertedAt: LocalDateTime)
case class EventId(value: Long) extends AnyVal
case class Event(id: EventId, organizationId: OrganizationId, name: String, description: Option[String], updatedAt: LocalDateTime, insertedAt: LocalDateTime)

// Fetcher to batch-fetch Organizations by their IDs
val organizationById: Fetcher[OrganizationId, Organization] =
  Fetcher((ids: Set[OrganizationId]) => 
    // Replace this with your actual database query logic
    ZIO.succeed(
      ids.map(id => 
        id -> Organization(
          id, 
          s"Organization ${id.value}", 
          Some(s"DE89370400440532013000"), 
          Some("COBADEFFXXX"), 
          LocalDateTime.now(), 
          LocalDateTime.now()
        )
      ).toMap
    )
  )

// Fetcher to batch-fetch Events by their IDs
val eventById: Fetcher[EventId, Event] =
  Fetcher((ids: Set[EventId]) => 
    // Replace this with your actual database query logic
    ZIO.succeed(
      ids.map(id => 
        id -> Event(
          id, 
          OrganizationId(id.value / 10), // Example: map event ID to org ID
          s"Event ${id.value}", 
          Some("A sample event description"), 
          LocalDateTime.now(), 
          LocalDateTime.now()
        )
      ).toMap
    )
  )

2. Use Fetcher.rel to Define Event → Organization Relationship

Since every Event has an organizationId, we can use Fetcher.rel to link Events to their parent Organizations. This fetcher will automatically collect all unique organizationIds from a set of Events, batch-fetch the corresponding Organizations, and map them back to the Events.

// Define a fetcher that gets the Organization for a given Event
val eventToOrganization: Fetcher[Event, Organization] =
  Fetcher.rel(
    sourceFetcher = eventById,       // Fetcher for the source entity (Event)
    targetFetcher = organizationById, // Fetcher for the related entity (Organization)
    getId = (event: Event) => event.organizationId // Extract the related ID from the source
  )

How to Use This Relationship Fetcher

Here's how to fetch a set of Events and their corresponding Organizations in one optimized query:

val fetchEventsWithOrgs: ZIO[Any, Nothing, Map[EventId, (Event, Organization)]] =
  for {
    // First fetch the Events we care about
    events <- ZIOQuery.run(eventById.fetch(Set(EventId(1), EventId(11), EventId(21))))
    // Batch-fetch all related Organizations in one go
    relatedOrgs <- ZIOQuery.run(eventToOrganization.fetch(events.values.toSet))
    // Pair each Event with its Organization
    pairedResults = events.map { case (eventId, event) =>
      eventId -> (event, relatedOrgs(event))
    }
  } yield pairedResults

3. Reverse Relationship: Organization → Events (One-to-Many)

Fetcher.rel also works for one-to-many relationships. First, define a fetcher that can retrieve all Events for a set of Organization IDs, then link it to the Organization fetcher.

// Fetcher to batch-fetch all Events for a set of Organization IDs
val eventsByOrganizationId: Fetcher[OrganizationId, List[Event]] =
  Fetcher((orgIds: Set[OrganizationId]) => 
    // Replace with your actual database query (e.g., SELECT * FROM events WHERE organization_id IN (...) grouped by org ID)
    ZIO.succeed(
      orgIds.map { orgId =>
        orgId -> List(
          Event(EventId(orgId.value * 10 + 1), orgId, s"Event ${orgId.value}-1", None, LocalDateTime.now(), LocalDateTime.now()),
          Event(EventId(orgId.value * 10 + 2), orgId, s"Event ${orgId.value}-2", None, LocalDateTime.now(), LocalDateTime.now())
        )
      }.toMap
    )
  )

// Define a fetcher that gets all Events for a given Organization
val organizationToEvents: Fetcher[Organization, List[Event]] =
  Fetcher.rel(
    sourceFetcher = organizationById,
    targetFetcher = eventsByOrganizationId,
    getId = (org: Organization) => org.id // Extract the Organization's ID to find its Events
  )

Key Takeaways

  • Fetcher.rel is all about composing fetchers for related entities to avoid N+1 queries.
  • It handles the heavy lifting of:
    1. Collecting all unique related IDs from a set of source entities
    2. Batch-fetching the related entities
    3. Mapping the results back to the original source entities
  • The pattern works the same for one-to-one, one-to-many, and even many-to-many relationships (you'd just adjust the target fetcher to return collections or mapped pairs).

内容的提问来源于stack exchange,提问作者mravey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:50:05