or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

active-record.mdcondition-builders.mdindex.mdkotlin-extensions.mdpagination.mdplugin-system.mdservice-layer.mdstatic-utilities.md

active-record.mddocs/

0

# Active Record Pattern

1

2

MyBatis-Plus Extension provides Active Record pattern support through the `Model` base class, enabling entity objects to perform their own database operations. This pattern allows entities to encapsulate both data and database behavior, providing a more object-oriented approach to data access.

3

4

## Core Components

5

6

### Model Base Class

7

8

The abstract `Model<T>` class that entities can extend to gain Active Record capabilities.

9

10

```java { .api }

11

public abstract class Model<T extends Model<?>> implements Serializable, Cloneable {

12

13

// Insert operations

14

public boolean insert();

15

public boolean insertOrUpdate();

16

17

// Delete operations

18

public boolean deleteById();

19

public boolean deleteById(Serializable id);

20

public boolean delete(Wrapper<T> queryWrapper);

21

22

// Update operations

23

public boolean updateById();

24

public boolean update(Wrapper<T> updateWrapper);

25

26

// Select operations

27

public T selectById();

28

public T selectById(Serializable id);

29

public T selectOne(Wrapper<T> queryWrapper);

30

public List<T> selectAll();

31

public List<T> selectList(Wrapper<T> queryWrapper);

32

public List<T> selectByIds(Collection<? extends Serializable> idList);

33

public List<T> selectByMap(Map<String, Object> columnMap);

34

public <E extends IPage<T>> E selectPage(E page, Wrapper<T> queryWrapper);

35

public long selectCount(Wrapper<T> queryWrapper);

36

37

// Utility operations

38

public SqlRunner sql();

39

protected abstract Serializable pkVal();

40

}

41

```

42

43

## Usage Examples

44

45

### Entity Definition

46

47

```java

48

@TableName("user")

49

public class User extends Model<User> {

50

51

@TableId(type = IdType.AUTO)

52

private Long id;

53

54

private String name;

55

private String email;

56

private Integer age;

57

private Boolean active;

58

private LocalDateTime createdTime;

59

private LocalDateTime updatedTime;

60

61

// Constructors

62

public User() {}

63

64

public User(String name, String email) {

65

this.name = name;

66

this.email = email;

67

this.active = true;

68

this.createdTime = LocalDateTime.now();

69

}

70

71

// Required: implement pkVal() method

72

@Override

73

protected Serializable pkVal() {

74

return this.id;

75

}

76

77

// Getters and setters

78

public Long getId() { return id; }

79

public void setId(Long id) { this.id = id; }

80

81

public String getName() { return name; }

82

public void setName(String name) { this.name = name; }

83

84

public String getEmail() { return email; }

85

public void setEmail(String email) { this.email = email; }

86

87

public Integer getAge() { return age; }

88

public void setAge(Integer age) { this.age = age; }

89

90

public Boolean getActive() { return active; }

91

public void setActive(Boolean active) { this.active = active; }

92

93

public LocalDateTime getCreatedTime() { return createdTime; }

94

public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; }

95

96

public LocalDateTime getUpdatedTime() { return updatedTime; }

97

public void setUpdatedTime(LocalDateTime updatedTime) { this.updatedTime = updatedTime; }

98

}

99

```

100

101

### Insert Operations

102

103

```java

104

// Create and insert new user

105

User newUser = new User("John Doe", "john@example.com");

106

newUser.setAge(30);

107

108

boolean inserted = newUser.insert();

109

if (inserted) {

110

System.out.println("User inserted with ID: " + newUser.getId());

111

}

112

113

// Insert or update based on primary key

114

User user = new User("Jane Smith", "jane@example.com");

115

user.setId(1L); // If ID exists, it will update; otherwise insert

116

boolean success = user.insertOrUpdate();

117

```

118

119

### Select Operations

120

121

```java

122

// Select by primary key

123

User user = new User();

124

User foundUser = user.selectById(1L);

125

126

if (foundUser != null) {

127

System.out.println("Found user: " + foundUser.getName());

128

}

129

130

// Select current instance by its ID

131

User user = new User();

132

user.setId(1L);

133

User reloaded = user.selectById(); // Uses the current instance's ID

134

135

// Select all users

136

User user = new User();

137

List<User> allUsers = user.selectAll();

138

139

// Select with conditions

140

User user = new User();

141

List<User> activeUsers = user.selectList(

142

new QueryWrapper<User>().eq("active", true)

143

);

144

145

// Select single user with conditions

146

User user = new User();

147

User activeUser = user.selectOne(

148

new QueryWrapper<User>()

149

.eq("active", true)

150

.eq("email", "john@example.com")

151

);

152

153

// Select by IDs

154

User user = new User();

155

List<User> users = user.selectByIds(Arrays.asList(1L, 2L, 3L));

156

157

// Select by column map

158

User user = new User();

159

Map<String, Object> conditions = new HashMap<>();

160

conditions.put("active", true);

161

conditions.put("age", 30);

162

List<User> users = user.selectByMap(conditions);

163

```

164

165

### Update Operations

166

167

```java

168

// Update by primary key

169

User user = new User();

170

user.setId(1L);

171

user.setName("Updated Name");

172

user.setEmail("updated@example.com");

173

user.setUpdatedTime(LocalDateTime.now());

174

175

boolean updated = user.updateById();

176

if (updated) {

177

System.out.println("User updated successfully");

178

}

179

180

// Update with conditions

181

User user = new User();

182

user.setActive(false);

183

user.setUpdatedTime(LocalDateTime.now());

184

185

boolean updated = user.update(

186

new UpdateWrapper<User>().eq("age", 25)

187

);

188

```

189

190

### Delete Operations

191

192

```java

193

// Delete by primary key (current instance)

194

User user = new User();

195

user.setId(1L);

196

boolean deleted = user.deleteById();

197

198

// Delete by specific ID

199

User user = new User();

200

boolean deleted = user.deleteById(2L);

201

202

// Delete with conditions

203

User user = new User();

204

boolean deleted = user.delete(

205

new QueryWrapper<User>()

206

.eq("active", false)

207

.lt("created_time", LocalDateTime.now().minusYears(1))

208

);

209

```

210

211

### Count Operations

212

213

```java

214

// Count all records

215

User user = new User();

216

long totalUsers = user.selectCount(null);

217

218

// Count with conditions

219

User user = new User();

220

long activeUsers = user.selectCount(

221

new QueryWrapper<User>().eq("active", true)

222

);

223

224

long adultUsers = user.selectCount(

225

new QueryWrapper<User>().ge("age", 18)

226

);

227

```

228

229

### Pagination with Active Record

230

231

```java

232

// Paginated selection

233

User user = new User();

234

Page<User> page = new Page<>(1, 10);

235

236

Page<User> result = user.selectPage(page,

237

new QueryWrapper<User>().eq("active", true).orderByDesc("created_time")

238

);

239

240

List<User> users = result.getRecords();

241

long total = result.getTotal();

242

System.out.println("Found " + total + " active users");

243

244

// Pagination without conditions

245

Page<User> allUsersPage = user.selectPage(new Page<>(1, 20), null);

246

```

247

248

## Advanced Usage

249

250

### Custom Entity Methods

251

252

```java

253

@TableName("user")

254

public class User extends Model<User> {

255

// ... fields and basic methods ...

256

257

// Custom business methods using Active Record

258

public boolean deactivate() {

259

this.active = false;

260

this.updatedTime = LocalDateTime.now();

261

return this.updateById();

262

}

263

264

public boolean activate() {

265

this.active = true;

266

this.updatedTime = LocalDateTime.now();

267

return this.updateById();

268

}

269

270

public List<User> findSimilarUsers() {

271

return this.selectList(

272

new QueryWrapper<User>()

273

.eq("age", this.age)

274

.ne("id", this.id)

275

.eq("active", true)

276

);

277

}

278

279

public boolean isAdult() {

280

return this.age != null && this.age >= 18;

281

}

282

283

public long countOlderUsers() {

284

if (this.age == null) return 0;

285

return this.selectCount(

286

new QueryWrapper<User>().gt("age", this.age)

287

);

288

}

289

290

public User findByEmail(String email) {

291

return this.selectOne(

292

new QueryWrapper<User>().eq("email", email)

293

);

294

}

295

}

296

```

297

298

### Usage of Custom Methods

299

300

```java

301

// Using custom entity methods

302

User user = new User("John", "john@example.com");

303

user.setAge(25);

304

user.insert();

305

306

// Deactivate user

307

boolean deactivated = user.deactivate();

308

309

// Find similar users

310

List<User> similarUsers = user.findSimilarUsers();

311

312

// Count older users

313

long olderCount = user.countOlderUsers();

314

315

// Find by email

316

User foundUser = new User().findByEmail("john@example.com");

317

```

318

319

### SQL Runner Integration

320

321

```java

322

@TableName("user")

323

public class User extends Model<User> {

324

// ... other methods ...

325

326

public List<Map<String, Object>> getDetailedStats() {

327

SqlRunner sqlRunner = this.sql();

328

return sqlRunner.selectList(

329

"SELECT age, COUNT(*) as count FROM user WHERE active = ? GROUP BY age ORDER BY age",

330

true

331

);

332

}

333

334

public boolean updateLastLoginTime() {

335

SqlRunner sqlRunner = this.sql();

336

int affected = sqlRunner.update(

337

"UPDATE user SET last_login = NOW() WHERE id = ?",

338

this.getId()

339

);

340

return affected > 0;

341

}

342

}

343

```

344

345

### Complex Queries

346

347

```java

348

// Complex query example

349

public class User extends Model<User> {

350

351

public List<User> findRecentActiveUsers(int days, int limit) {

352

return this.selectList(

353

new QueryWrapper<User>()

354

.eq("active", true)

355

.ge("last_login", LocalDateTime.now().minusDays(days))

356

.orderByDesc("last_login")

357

.last("LIMIT " + limit)

358

);

359

}

360

361

public Page<User> searchUsers(String keyword, int page, int size) {

362

return this.selectPage(

363

new Page<>(page, size),

364

new QueryWrapper<User>()

365

.and(wrapper -> wrapper

366

.like("name", keyword)

367

.or()

368

.like("email", keyword)

369

)

370

.eq("active", true)

371

.orderByDesc("created_time")

372

);

373

}

374

}

375

```

376

377

## Working with Relationships

378

379

While Active Record pattern works best with single entities, you can still handle relationships:

380

381

```java

382

@TableName("user")

383

public class User extends Model<User> {

384

// ... basic fields ...

385

386

// Get user's orders (assuming Order entity exists)

387

public List<Order> getOrders() {

388

Order orderModel = new Order();

389

return orderModel.selectList(

390

new QueryWrapper<Order>().eq("user_id", this.getId())

391

);

392

}

393

394

// Get user's active orders

395

public List<Order> getActiveOrders() {

396

Order orderModel = new Order();

397

return orderModel.selectList(

398

new QueryWrapper<Order>()

399

.eq("user_id", this.getId())

400

.eq("status", "ACTIVE")

401

.orderByDesc("created_time")

402

);

403

}

404

405

// Count user's orders

406

public long getOrderCount() {

407

Order orderModel = new Order();

408

return orderModel.selectCount(

409

new QueryWrapper<Order>().eq("user_id", this.getId())

410

);

411

}

412

}

413

```

414

415

## Best Practices

416

417

### 1. Always Implement pkVal()

418

419

```java

420

@Override

421

protected Serializable pkVal() {

422

return this.id; // Return the primary key value

423

}

424

```

425

426

### 2. Handle Null Checks

427

428

```java

429

public boolean updateIfExists() {

430

if (this.getId() == null) {

431

return false; // Cannot update without ID

432

}

433

return this.updateById();

434

}

435

436

public User reloadFromDatabase() {

437

if (this.getId() == null) {

438

return null;

439

}

440

return this.selectById();

441

}

442

```

443

444

### 3. Use Transactions for Complex Operations

445

446

```java

447

@Transactional

448

public boolean transferToInactiveStatus() {

449

// Update user status

450

this.active = false;

451

this.updatedTime = LocalDateTime.now();

452

boolean userUpdated = this.updateById();

453

454

if (!userUpdated) {

455

throw new RuntimeException("Failed to update user");

456

}

457

458

// Update related data using SQL Runner

459

SqlRunner sqlRunner = this.sql();

460

int affected = sqlRunner.update(

461

"UPDATE user_sessions SET active = 0 WHERE user_id = ?",

462

this.getId()

463

);

464

465

return affected >= 0;

466

}

467

```

468

469

### 4. Validation Methods

470

471

```java

472

public boolean isValid() {

473

return this.name != null && !this.name.trim().isEmpty() &&

474

this.email != null && this.email.contains("@");

475

}

476

477

public boolean saveIfValid() {

478

if (!isValid()) {

479

return false;

480

}

481

return this.insert();

482

}

483

```

484

485

## Error Handling

486

487

```java

488

public class User extends Model<User> {

489

490

public boolean safeUpdate() {

491

try {

492

if (this.getId() == null) {

493

System.err.println("Cannot update user without ID");

494

return false;

495

}

496

497

return this.updateById();

498

499

} catch (Exception e) {

500

System.err.println("Error updating user: " + e.getMessage());

501

return false;

502

}

503

}

504

505

public User safeSelectById(Long id) {

506

try {

507

return this.selectById(id);

508

} catch (Exception e) {

509

System.err.println("Error selecting user by ID " + id + ": " + e.getMessage());

510

return null;

511

}

512

}

513

}

514

```

515

516

## Performance Considerations

517

518

- Active Record is convenient but may not be suitable for bulk operations

519

- For large datasets, consider using service layer methods instead

520

- Use `selectList()` with conditions rather than `selectAll()` and filtering in Java

521

- Be cautious with custom methods that might cause N+1 query problems

522

- Cache frequently accessed read-only data at the application level