组件与整洁架构一一对应,依赖方向始终指向内层。
定义独立于框架和数据库的业务实体与关系——所有其他层都从中派生的稳定内核。
自动化数据组装编排——resolve 批量加载缺失数据,post 在树就绪后计算派生字段。
用统一接口抽象数据源。从 SQLAlchemy 切换到 Django 或 Tortoise ORM,实体和响应层无需改动。
用声明式数据加载替代手动循环查询。
# Sprint has 10 tasks, each needs owner
for task in sprint.tasks:
task.owner = await get_user(task.owner_id)
# 10 queries!
class TaskView(BaseModel):
owner_id: int
owner: Optional[UserView] = None
def resolve_owner(self, loader=Loader(user_loader)):
return loader.load(self.owner_id)
# 1 query!
class UserEntity(BaseModel, BaseEntity):
id: int
name: str
class TaskEntity(BaseModel, BaseEntity):
__relationships__ = [
Relationship(fk='owner_id', target=UserEntity, loader=user_loader),
]
id: int
name: str
owner_id: int
class StoryEntity(BaseModel, BaseEntity):
__relationships__ = [
Relationship(fk='id', target=list[TaskEntity], loader=task_loader),
]
id: int
name: str
class TaskSummary(DefineSubset):
__subset__ = (TaskEntity, ('id', 'name'))
owner: Optional[UserEntity] = None # implicit match, no AutoLoad
class StoryView(DefineSubset):
__subset__ = (StoryEntity, ('id', 'name'))
tasks: list[TaskSummary] = [] # implicit match
@router.get("/stories")
async def get_stories():
stories = [StoryView.model_validate(s)
for s in await get_stories_from_db()]
return await Resolver().resolve(stories)
[
{
"id": 1,
"name": "Sprint 1",
"tasks": [
{
"id": 101,
"name": "Implement login",
"owner": { "id": 1, "name": "Alice" }
}
]
}
]
从简单开始,按需扩展。每个概念都建立在前一个之上。
从加载关联数据到生成 GraphQL API — 一个库全覆盖。
通过 DataLoader 模式自动批量查询,100 次查询变 1 次。
在嵌套数据就绪后计算派生字段:计数、聚合、格式化。
ExposeAs / SendTo / Collector,无需手写遍历逻辑即可跨层传递数据。
集中管理关系声明,跨模型复用,同时驱动 GraphQL 和 MCP。
从 ER 图自动生成 GraphQL schema 和 resolver。
通过 MCP 协议将 GraphQL API 暴露给 AI 代理。
与你现有的框架和 ORM 无缝集成。
每个功能都有覆盖——从核心解析到 ER 图、跨层数据流和边界情况。
Entity-First 架构让 API 独立于数据库变更,不再级联重构。
每次提交通过自动化 CI,兼容 Python 3.10–3.13。