实体查询

Testing Is Documentation

tests/Database/Ddd/SelectTest.php实体查询 - 图1

在设计实体的时候,我们是这样想的,查询不属于实体的一部分而应该是独立的,所以实体查询被抽象出来了。

Uses

  1. <?php
  2. use Exception;
  3. use Leevel\Collection\Collection;
  4. use Leevel\Database\Ddd\Entity;
  5. use Leevel\Database\Ddd\Select;
  6. use Leevel\Database\Page;
  7. use Tests\Database\DatabaseTestCase as TestCase;
  8. use Tests\Database\Ddd\Entity\CompositeId;
  9. use Tests\Database\Ddd\Entity\Relation\Post;

基本使用方法

  1. public function testBase(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $select = new Select(new Post());
  16. $post = $select->findEntity(1);
  17. $entity = $select->entity();
  18. $this->assertInstanceof(Post::class, $post);
  19. $this->assertSame(1, $post->id);
  20. $this->assertSame(1, $post->userId);
  21. $this->assertSame('hello world', $post->title);
  22. $this->assertSame('post summary', $post->summary);
  23. $this->assertInstanceof(Entity::class, $entity);
  24. }

findEntity 通过主键查找实体

  1. public function testFindEntity(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $select = new Select(new Post());
  16. $post = $select->findEntity(1);
  17. $this->assertInstanceof(Post::class, $post);
  18. $this->assertSame(1, $post->id);
  19. $this->assertSame(1, $post->userId);
  20. $this->assertSame('hello world', $post->title);
  21. $this->assertSame('post summary', $post->summary);
  22. }

复合主键请使用 where 条件查询

  1. public function testFindEntityForCompositeId(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('composite_id')
  8. ->insert([
  9. 'id1' => 1,
  10. 'id2' => 2,
  11. 'name' => 'hello liu',
  12. ])
  13. );
  14. $select = new Select(new CompositeId());
  15. $entity = $select->where(['id1' => 1, 'id2' => 2])->findOne();
  16. $this->assertInstanceof(CompositeId::class, $entity);
  17. $this->assertSame(1, $entity->id1);
  18. $this->assertSame(2, $entity->id2);
  19. $this->assertSame('hello liu', $entity->name);
  20. }

findOrFail 通过主键查找实体,未找到则抛出异常

  1. public function testFindOrFail(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $select = new Select(new Post());
  16. $post = $select->findOrFail(1);
  17. $this->assertInstanceof(Post::class, $post);
  18. $this->assertSame(1, $post->id);
  19. $this->assertSame(1, $post->userId);
  20. $this->assertSame('hello world', $post->title);
  21. $this->assertSame('post summary', $post->summary);
  22. }

findOrFail 通过主键查找实体,未找到则抛出异常例子

  1. public function testFindOrFailThrowsException(): void
  2. {
  3. $this->expectException(\Leevel\Database\Ddd\EntityNotFoundException::class);
  4. $this->expectExceptionMessage(
  5. 'Entity `Tests\\Database\\Ddd\\Entity\\Relation\\Post` was not found.'
  6. );
  7. $select = new Select(new Post());
  8. $post = $select->findOrFail(1);
  9. }

findMany 通过主键查找多个实体

  1. public function testFindMany(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select(new Post());
  27. $posts = $select->findMany([1, 2]);
  28. $this->assertInstanceof(Collection::class, $posts);
  29. $this->assertCount(2, $posts);
  30. $post1 = $posts[0];
  31. $this->assertInstanceof(Post::class, $post1);
  32. $this->assertSame(1, $post1->userId);
  33. $this->assertSame('hello world', $post1->title);
  34. $this->assertSame('post summary', $post1->summary);
  35. $post2 = $posts[1];
  36. $this->assertInstanceof(Post::class, $post2);
  37. $this->assertSame(1, $post2->userId);
  38. $this->assertSame('hello world', $post2->title);
  39. $this->assertSame('post summary', $post2->summary);
  40. }

findMany 通过主键查找多个实体未找到数据返回空集合

  1. public function testFindManyWithoutResults(): void
  2. {
  3. $select = new Select(new Post());
  4. $posts = $select->findMany([1, 2]);
  5. $this->assertInstanceof(Collection::class, $posts);
  6. $this->assertCount(0, $posts);
  7. }

实体查询默认不带软删除数据

  1. public function testEntityDefaultWithoutSoftDeleted(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select($post = Post::select()->findEntity(1));
  27. $posts = $select->findAll();
  28. $sql = <<<'eot'
  29. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  30. eot;
  31. $this->assertSame(
  32. $sql,
  33. $select->getLastSql(),
  34. );
  35. $this->assertInstanceof(Collection::class, $posts);
  36. $this->assertCount(2, $posts);
  37. $this->assertFalse($post->softDeleted());
  38. $this->assertSame(1, Post::softDestroy([1]));
  39. $this->assertFalse($post->softDeleted());
  40. $posts = $select->findAll();
  41. $sql = <<<'eot'
  42. SQL: [72] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at_1 | Params: 1 | Key: Name: [17] :post_delete_at_1 | paramno=0 | name=[17] ":post_delete_at_1" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  43. eot;
  44. $this->assertSame(
  45. $sql,
  46. $select->getLastSql(),
  47. );
  48. $this->assertInstanceof(Collection::class, $posts);
  49. $this->assertCount(1, $posts);
  50. $posts = Post::select()->findAll();
  51. $sql = <<<'eot'
  52. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  53. eot;
  54. $this->assertSame(
  55. $sql,
  56. $select->getLastSql(),
  57. );
  58. $this->assertInstanceof(Collection::class, $posts);
  59. $this->assertCount(1, $posts);
  60. }

withSoftDeleted 包含软删除数据的实体查询对象(实体发起)

  1. public function testEntityWithSoftDeleted(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select($post = Post::select()->findEntity(1));
  27. $posts = $select->findAll();
  28. $sql = <<<'eot'
  29. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  30. eot;
  31. $this->assertSame(
  32. $sql,
  33. $select->getLastSql(),
  34. );
  35. $this->assertInstanceof(Collection::class, $posts);
  36. $this->assertCount(2, $posts);
  37. $this->assertFalse($post->softDeleted());
  38. $this->assertSame(1, Post::softDestroy([1]));
  39. $this->assertFalse($post->softDeleted());
  40. $posts = $select->findAll();
  41. $sql = <<<'eot'
  42. SQL: [72] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at_1 | Params: 1 | Key: Name: [17] :post_delete_at_1 | paramno=0 | name=[17] ":post_delete_at_1" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  43. eot;
  44. $this->assertSame(
  45. $sql,
  46. $select->getLastSql(),
  47. );
  48. $this->assertInstanceof(Collection::class, $posts);
  49. $this->assertCount(1, $posts);
  50. $posts = Post::withSoftDeleted()->findAll();
  51. $sql = <<<'eot'
  52. SQL: [27] SELECT `post`.* FROM `post` | Params: 0 (SELECT `post`.* FROM `post`)
  53. eot;
  54. $this->assertSame(
  55. $sql,
  56. $select->getLastSql(),
  57. );
  58. $this->assertInstanceof(Collection::class, $posts);
  59. $this->assertCount(2, $posts);
  60. }

onlySoftDeleted 仅仅包含软删除数据的实体查询对象(实体发起)

  1. public function testEntityOnlySoftDeleted(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select($post = Post::select()->findEntity(1));
  27. $posts = $select->findAll();
  28. $sql = <<<'eot'
  29. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  30. eot;
  31. $this->assertSame(
  32. $sql,
  33. $select->getLastSql(),
  34. );
  35. $this->assertInstanceof(Collection::class, $posts);
  36. $this->assertCount(2, $posts);
  37. $this->assertFalse($post->softDeleted());
  38. $this->assertSame(1, Post::softDestroy([1]));
  39. $this->assertFalse($post->softDeleted());
  40. $posts = $select->findAll();
  41. $sql = <<<'eot'
  42. SQL: [72] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at_1 | Params: 1 | Key: Name: [17] :post_delete_at_1 | paramno=0 | name=[17] ":post_delete_at_1" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  43. eot;
  44. $this->assertSame(
  45. $sql,
  46. $select->getLastSql(),
  47. );
  48. $this->assertInstanceof(Collection::class, $posts);
  49. $this->assertCount(1, $posts);
  50. $posts = Post::onlySoftDeleted()->findAll();
  51. $sql = <<<'eot'
  52. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` > :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` > 0)
  53. eot;
  54. $this->assertSame(
  55. $sql,
  56. $select->getLastSql(),
  57. );
  58. $this->assertInstanceof(Collection::class, $posts);
  59. $this->assertCount(1, $posts);
  60. }

onlySoftDeleted 包含软删除数据的实体查询对象(实体查询发起)

  1. public function testWithSoftDeleted(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select($post = Post::select()->findEntity(1));
  27. $posts = $select->findAll();
  28. $sql = <<<'eot'
  29. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  30. eot;
  31. $this->assertSame(
  32. $sql,
  33. $select->getLastSql(),
  34. );
  35. $this->assertInstanceof(Collection::class, $posts);
  36. $this->assertCount(2, $posts);
  37. $this->assertFalse($post->softDeleted());
  38. $this->assertSame(1, Post::softDestroy([1]));
  39. $this->assertFalse($post->softDeleted());
  40. $posts = $select->findAll();
  41. $sql = <<<'eot'
  42. SQL: [72] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at_1 | Params: 1 | Key: Name: [17] :post_delete_at_1 | paramno=0 | name=[17] ":post_delete_at_1" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  43. eot;
  44. $this->assertSame(
  45. $sql,
  46. $select->getLastSql(),
  47. );
  48. $this->assertInstanceof(Collection::class, $posts);
  49. $this->assertCount(1, $posts);
  50. $posts = $select->withSoftDeleted()->findAll();
  51. $sql = <<<'eot'
  52. SQL: [27] SELECT `post`.* FROM `post` | Params: 0 (SELECT `post`.* FROM `post`)
  53. eot;
  54. $this->assertSame(
  55. $sql,
  56. $select->getLastSql(),
  57. );
  58. $this->assertInstanceof(Collection::class, $posts);
  59. $this->assertCount(2, $posts);
  60. }

onlySoftDeleted 仅仅包含软删除数据的实体查询对象(实体查询发起)

  1. public function testOnlySoftDeleted(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select($post = Post::select()->findEntity(1));
  27. $posts = $select->findAll();
  28. $sql = <<<'eot'
  29. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  30. eot;
  31. $this->assertSame(
  32. $sql,
  33. $select->getLastSql(),
  34. );
  35. $this->assertInstanceof(Collection::class, $posts);
  36. $this->assertCount(2, $posts);
  37. $this->assertFalse($post->softDeleted());
  38. $this->assertSame(1, Post::softDestroy([1]));
  39. $this->assertFalse($post->softDeleted());
  40. $posts = $select->findAll();
  41. $sql = <<<'eot'
  42. SQL: [72] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at_1 | Params: 1 | Key: Name: [17] :post_delete_at_1 | paramno=0 | name=[17] ":post_delete_at_1" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0)
  43. eot;
  44. $this->assertSame(
  45. $sql,
  46. $select->getLastSql(),
  47. );
  48. $this->assertInstanceof(Collection::class, $posts);
  49. $this->assertCount(1, $posts);
  50. $posts = $select->onlySoftDeleted()->findAll();
  51. $sql = <<<'eot'
  52. SQL: [70] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` > :post_delete_at | Params: 1 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` > 0)
  53. eot;
  54. $this->assertSame(
  55. $sql,
  56. $select->getLastSql(),
  57. );
  58. $this->assertInstanceof(Collection::class, $posts);
  59. $this->assertCount(1, $posts);
  60. }

getLastSql 获取最近一次查询的 SQL 语句

  1. public function testLastSql(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $select = new Select(new Post());
  16. $post = $select->findEntity(1);
  17. $this->assertInstanceof(Post::class, $post);
  18. $this->assertSame(1, $post->id);
  19. $this->assertSame(1, $post->userId);
  20. $this->assertSame('hello world', $post->title);
  21. $this->assertSame('post summary', $post->summary);
  22. $sql = <<<'eot'
  23. SQL: [105] SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = :post_delete_at AND `post`.`id` = :post_id LIMIT 1 | Params: 2 | Key: Name: [15] :post_delete_at | paramno=0 | name=[15] ":post_delete_at" | is_param=1 | param_type=1 | Key: Name: [8] :post_id | paramno=1 | name=[8] ":post_id" | is_param=1 | param_type=1 (SELECT `post`.* FROM `post` WHERE `post`.`delete_at` = 0 AND `post`.`id` = 1 LIMIT 1)
  24. eot;
  25. $this->assertSame(
  26. $sql,
  27. $select->databaseConnect()->getLastSql(),
  28. );
  29. }

withoutPreLoadsResult 获取不执行预载入的查询结果

  1. public function testWithoutPreLoadsResult(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $select = new Select(new Post());
  16. $post = Select::withoutPreLoadsResult(function () use ($select) {
  17. return $select->findEntity(1);
  18. });
  19. $this->assertInstanceof(Post::class, $post);
  20. $this->assertSame(1, $post->id);
  21. $this->assertSame(1, $post->userId);
  22. $this->assertSame('hello world', $post->title);
  23. $this->assertSame('post summary', $post->summary);
  24. }

eager 添加预载入关联查询

  1. public function testPreLoadPage(): void
  2. {
  3. $connect = $this->createDatabaseConnect();
  4. $this->assertSame(
  5. 1,
  6. $connect
  7. ->table('post')
  8. ->insert([
  9. 'title' => 'hello world',
  10. 'user_id' => 1,
  11. 'summary' => 'post summary',
  12. 'delete_at' => 0,
  13. ])
  14. );
  15. $this->assertSame(
  16. 2,
  17. $connect
  18. ->table('post')
  19. ->insert([
  20. 'title' => 'hello world',
  21. 'user_id' => 1,
  22. 'summary' => 'post summary',
  23. 'delete_at' => 0,
  24. ])
  25. );
  26. $select = new Select($post = Post::select()->findEntity(1));
  27. $select->eager(['user']);
  28. $page = $select->page(1, 10);
  29. $sql = <<<'eot'
  30. SQL: [63] SELECT `user`.* FROM `user` WHERE `user`.`id` IN (:user_id_in0) | Params: 1 | Key: Name: [12] :user_id_in0 | paramno=0 | name=[12] ":user_id_in0" | is_param=1 | param_type=1 (SELECT `user`.* FROM `user` WHERE `user`.`id` IN (1))
  31. eot;
  32. $this->assertSame(
  33. $sql,
  34. $select->getLastSql(),
  35. );
  36. $this->assertInstanceof(Page::class, $page);
  37. $data = $page->getData();
  38. $this->assertCount(2, $data);
  39. $this->assertInstanceof(Collection::class, $data);
  40. $pageData = $page->toArray();
  41. $this->assertCount(2, $pageData['data']);
  42. $this->assertInstanceof(Collection::class, $pageData['data']);
  43. $data = <<<'eot'
  44. {
  45. "per_page": 10,
  46. "current_page": 1,
  47. "total_page": 1,
  48. "total_record": 2,
  49. "total_macro": false,
  50. "from": 0,
  51. "to": 2
  52. }
  53. eot;
  54. $this->assertSame(
  55. $data,
  56. $this->varJson(
  57. $pageData['page']
  58. )
  59. );
  60. }