Skip to content

预加载关联 (Eager Loading)

预加载是一种在查询主实体时同时加载其关联数据的技术。IBest ORM 提供了强大的预加载功能,支持嵌套关联和复杂查询场景。

基础用法

使用 with() 方法

typescript
// 预加载单个关联
const user = orm.query(User)
  .with('profile')
  .first();

// 预加载多个关联
const users = orm.query(User)
  .with('profile')
  .with('orders')
  .with('roles')
  .find();

详细用法指南

查询方法

typescript
// first() - 查询单条记录及关联
const user = orm.query(User)
  .with('profile')
  .where({ id: 1 })
  .first();

// find() - 查询多条记录及关联
const users = orm.query(User)
  .with('profile')
  .with('articles')
  .find();

复杂嵌套示例

typescript
// 查询用户的完整信息:档案、文章、用户角色
const user = orm.query(User)
  .with('profile')
  .with('articles')
  .with('roles')
  .where({ id: 1 })
  .first();

console.log('完整用户数据:', user);
// 输出:
// {
//   id: 1,
//   name: "张三",
//   email: "zhangsan@example.com",
//   profile: {
//     id: 1,
//     userId: 1,
//     avatar: "avatar1.jpg",
//     bio: "热爱技术的程序员"
//   },
//   articles: [
//     {
//       id: 1,
//       title: "TypeScript入门指南",
//       content: "TypeScript是JavaScript的超集...",
//       authorId: 1
//     }
//   ],
//   roles: [
//     {
//       id: 1,
//       name: "admin",
//       description: "管理员"
//     }
//   ]
// }

不同关联类型的预加载

Has One 关联预加载

typescript
// 用户档案(一对一)
const user = orm.query(User)
  .with('profile')
  .where({ id: 1 })
  .first();

// 结果中 profile 是单个对象或 undefined
console.log('用户档案:', user?.profile);

Has Many 关联预加载

typescript
// 用户文章(一对多)
const user = orm.query(User)
  .with('articles')
  .where({ id: 1 })
  .first();

// 结果中 articles 是数组
console.log('文章数量:', user?.articles?.length || 0);

Belongs To 关联预加载

typescript
// 文章作者(多对一)
const article = orm.query(Article)
  .with('author')
  .where({ id: 1 })
  .first();

// 结果中 author 是单个对象或 undefined
console.log('文章作者:', article?.author?.name);

Many To Many 关联预加载

typescript
// 用户角色(多对多)
const user = orm.query(User)
  .with('roles')
  .where({ id: 1 })
  .first();

// 结果中 roles 是数组
console.log('角色列表:', user?.roles?.map(role => role.name));

批量预加载

typescript
// 查询所有用户及其档案和文章
const users = orm.query(User)
  .with('profile')
  .with('articles')
  .find();

users.forEach(user => {
  console.log(`用户: ${user.name}`);
  console.log(`档案: ${user.profile?.bio || '无'}`);
  console.log(`文章数: ${user.articles?.length || 0}`);
  console.log('---');
});

// 分页查询与预加载
const usersPage = orm.query(User)
  .with('profile')
  .with('articles')
  .limit(10)
  .offset(0)
  .find();

条件查询与预加载

typescript
// 查询活跃用户及其文章
const activeUsers = orm.query(User)
  .with('articles')
  .where({ status: 'active' })
  .find();

// 多条件查询
const filteredUsers = orm.query(User)
  .with('profile')
  .with('articles')
  .where({ status: 'active' })
  .where({ age: { gte: 18 } })
  .find();

性能优化

选择性预加载

只预加载需要的关联,避免不必要的数据传输:

typescript
// 好的做法:只预加载需要的关联
const users = orm.query(User)
  .with('profile')  // 只预加载用户资料
  .find();

// 避免:预加载所有关联
const users = orm.query(User)
  .with('profile')
  .with('orders')
  .with('roles')
  .with('permissions')
  .with('settings')
  .find();

实际应用示例

用户详情页面

typescript
function getUserDetails(userId: number) {
  const user = orm.query(User)
    .with('profile')
    .with('orders')
    .with('roles')
    .where({ id: userId })
    .first();

  return {
    user: {
      id: user?.id,
      name: user?.name,
      email: user?.email,
      bio: user?.profile?.bio,
      avatar: user?.profile?.avatar
    },
    orders: user?.orders?.map(order => ({
      id: order.id,
      productName: order.productName,
      amount: order.amount
    })) || [],
    roles: user?.roles?.map(role => role.name) || []
  };
}

订单列表页面

typescript
function getOrdersList(page: number = 1, limit: number = 20) {
  const orders = orm.query(Order)
    .with('user')
    .orderBy('createdAt', 'desc')
    .offset((page - 1) * limit)
    .limit(limit)
    .find();

  return orders.map(order => ({
    id: order.id,
    productName: order.productName,
    amount: order.amount,
    userName: order.user?.name
  }));
}

仪表板统计

typescript
function getDashboardStats() {
  const users = orm.query(User)
    .with('orders')
    .with('roles')
    .find();

  return {
    totalUsers: users.length,
    totalOrders: users.reduce((sum, user) => sum + (user.orders?.length || 0), 0),
    adminUsers: users.filter(user =>
      user.roles?.some(role => role.name === 'admin')
    ).length
  };
}

常见问题

Q: 预加载的关联为空数组或 undefined?

A: 检查以下几点:

  1. 关联配置是否正确(外键、目标类等)
  2. 数据库中是否存在关联数据
  3. 外键值是否正确

Q: 预加载性能较差?

A: 优化建议:

  1. 只预加载必需的关联
  2. 使用分页限制结果集大小
  3. 避免预加载过多关联