Getting Started
This guide will help you get up and running with DB plugin quickly. You'll learn how to create your first domain objects, and perform basic operations.
Creating Your First Record Class
A Record is your domain object that maps to database storage. Here's a simple example:
1import java.util.ArrayList;2import java.util.Date;3import java.util.List;45import com.psddev.dari.db.Record;67public class Article extends Record {89@Indexed10private String title;1112@Indexed13@Required14private Author author;1516@Indexed17private Date publishDate;1819private String content;2021private List<String> tags;2223// Getters and setters24public String getTitle() {25return title;26}2728public void setTitle(String title) {29this.title = title;30}3132public Author getAuthor() {33return author;34}3536public void setAuthor(Author author) {37this.author = author;38}3940public Date getPublishDate() {41return publishDate;42}4344public void setPublishDate(Date publishDate) {45this.publishDate = publishDate;46}4748public String getContent() {49return content;50}5152public void setContent(String content) {53this.content = content;54}5556public List<String> getTags() {57if (tags == null) {58tags = new ArrayList<>();59}60return tags;61}6263public void setTags(List<String> tags) {64this.tags = tags;65}6667// Optional: Override getLabel for display purposes68@Override69public String getLabel() {70return title != null ? title : "Untitled Article";71}72}
1import com.psddev.dari.db.Record;23public class Author extends Record {45@Indexed6@Required7private String name;89@Indexed10private String email;1112private String bio;1314// Getters and setters15public String getName() {16return name;17}1819public void setName(String name) {20this.name = name;21}2223public String getEmail() {24return email;25}2627public void setEmail(String email) {28this.email = email;29}3031public String getBio() {32return bio;33}3435public void setBio(String bio) {36this.bio = bio;37}3839@Override40public String getLabel() {41return name;42}43}
Important Annotations
@Indexed- Makes a field queryable. Required for any field you want to filter/sort by.@Required- Field must have a value before saving.@Embedded- Always stores the object inline (no separate table/document).
Basic CRUD Operations
Creating and Saving Objects
1// Create a new author2Author author = new Author();3author.setName("John Doe");4author.setEmail("john@example.com");5author.setBio("Experienced writer and developer");6author.save();78// Create an article9Article article = new Article();10article.setTitle("Getting Started with DB plugin");11article.setAuthor(author); // Reference to author12article.setPublishDate(new Date());13article.setContent("This is the content of the article...");14article.setTags(Arrays.asList("database", "tutorial", "java"));15article.save();
Reading Objects by ID
Every Record has a unique ID (UUID):
1// Get the ID2UUID articleId = article.getId();34// Later, load by ID5Article loaded = Query.from(Article.class)6.where("_id = ?", articleId)7.first();
Querying Objects
1// Find all articles2List<Article> allArticles = Query.from(Article.class)3.selectAll();
1// Find articles by author2List<Article> johnArticles = Query.from(Article.class)3.where("author = ?", author)4.selectAll();
1// Find articles by author name (path-based query)2List<Article> authorArticles = Query.from(Article.class)3.where("author/name = ?", "John Doe")4.selectAll();
1// Find recent articles2Date recentCutoff = DateUtils.addDays(new Date(), -7);3List<Article> recentArticles = Query.from(Article.class)4.where("publishDate > ?", recentCutoff)5.sortDescending("publishDate")6.selectAll();
1// Paginated results2PaginatedResult<Article> firstPage = Query.from(Article.class)3.sortDescending("publishDate")4.select(0, 10); // Skip 0, limit 10
1// Count articles2long totalArticles = Query.from(Article.class)3.count();
Updating Objects
1// Load the object2Article loadedArticle = Query.from(Article.class)3.where("_id = ?", articleId)4.first();56// Modify fields7loadedArticle.setTitle("Updated Title");8loadedArticle.getTags().add("updated");910// Save changes11loadedArticle.save();
Deleting Objects
1// Delete a single object2article.delete();
1// Delete by query2Query.from(Article.class)3.where("publishDate < ?", cutoffDate)4.deleteAll();
Working with References
DB plugin automatically handles relationships between objects:
1// Save author first2Author author = new Author();3author.setName("Jane Smith");4author.save();56// Create article with reference7Article article = new Article();8article.setTitle("My Article");9article.setAuthor(author); // This stores a reference, not a copy10article.save();1112// Later, when you load the article13Article loaded = Query.from(Article.class)14.where("_id = ?", article.getId())15.first();1617// The author is lazy-loaded18Author loadedAuthor = loaded.getAuthor(); // Database query happens here19System.out.println(loadedAuthor.getName()); // "Jane Smith"
Reference Resolution Options
1// Reference-only query (don't load full objects)2List<Article> articleRefs = Query.from(Article.class)3.resolveToReferenceOnly()4.selectAll();5// articleRefs contains lightweight reference objects
Using Transactions
For multiple operations that should succeed or fail together:
1Database db = Database.Static.getDefault();23try {4db.beginWrites();56// Create multiple objects7Author author = new Author();8author.setName("John Doe");9author.save();1011Article article1 = new Article();12article1.setTitle("First Article");13article1.setAuthor(author);14article1.save();1516Article article2 = new Article();17article2.setTitle("Second Article");18article2.setAuthor(author);19article2.save();2021// Commit all changes22db.commitWrites();2324} finally {25// Always clean up (rolls back on exception)26db.endWrites();27}
Validation
DB plugin validates objects before saving:
1import common.Author;2import com.psddev.dari.db.Record;3import com.psddev.dari.db.Recordable;45public class Article extends Record {67@Recordable.Required8@Recordable.Maximum(200)9private String title;1011@Recordable.Required12private Author author;1314@Override15protected void onValidate() {16if (title != null && title.contains("spam")) {17getState().addError(18getState().getField("title"),19new IllegalArgumentException("Title contains spam")20);21}22}2324public String getTitle() {25return title;26}2728public void setTitle(String title) {29this.title = title;30}3132public Author getAuthor() {33return author;34}3536public void setAuthor(Author author) {37this.author = author;38}39}
1// Attempting to save an invalid object throws ValidationException2Article article = new Article();3// article.setTitle(null); // Required field missing4// article.setAuthor(null); // Also required56try {7article.save();8} catch (ValidationException e) {9// Handle validation errors10for (ObjectField field : e.getStates()11.stream()12.map(State::getErrorFields)13.flatMap(Collection::stream)14.collect(Collectors.toList())) {15System.out.println("Error in " + field.getInternalName() + ": "16+ field.getState().getFieldErrors(field));17}18}
Lifecycle Hooks
Override lifecycle methods to add custom behavior:
1import java.util.Date;23import com.psddev.dari.db.Record;45public class Article extends Record {67private String title;8private Date publishDate;910@Override11protected void beforeSave() {12// Called before validation and save13if (publishDate == null) {14publishDate = new Date();15}16}1718@Override19protected void afterSave() {20// Called after successful save21System.out.println("Article saved: " + getLabel());22}2324@Override25protected void beforeDelete() {26// Called before delete27System.out.println("Deleting article: " + getLabel());28}2930@Override31protected void afterDelete() {32// Called after successful delete33System.out.println("Article deleted");34}3536public String getTitle() {37return title;38}3940public void setTitle(String title) {41this.title = title;42}4344public Date getPublishDate() {45return publishDate;46}4748public void setPublishDate(Date publishDate) {49this.publishDate = publishDate;50}51}
Common Query Patterns
Search by Multiple Tags
1// Find articles with any of the specified tags2List<Article> articles = Query.from(Article.class)3.where("tags = ?", Arrays.asList("java", "database", "tutorial"))4.selectAll();56// Find articles with all specified tags (requires all)7// This requires querying differently - use repeated predicates8Query<Article> query = Query.from(Article.class);9for (String tag : Arrays.asList("java", "database")) {10query.and("tags = ?", tag);11}12List<Article> articlesWithAllTags = query.selectAll();
Counting and Statistics
1// Total count2long totalArticles = Query.from(Article.class).count();34// Conditional count5long publishedCount = Query.from(Article.class)6.where("publishDate != missing")7.count();89// Count by author10long johnCount = Query.from(Article.class)11.where("author/name = ?", "John Doe")12.count();
Best Practices
1. Always Index Queryable Fields
1// Good2@Indexed3private String title;45// Bad - can't query this field6private String title;
2. Use Transactions for Multiple Writes
1// Good - atomic2db.beginWrites();3try {4Author author = new Author();5author.save();6Article article = new Article();7article.save();8db.commitWrites();9} finally {10db.endWrites();11}1213// Bad - non-atomic, could partially succeed14Author author2 = new Author();15author2.save();16Article article2 = new Article();17article2.save();
3. Use Pagination for Large Result Sets
1// Good - memory efficient2PaginatedResult<Article> page = Query.from(Article.class)3.select(offset, limit);45// Bad - loads everything into memory6List<Article> all = Query.from(Article.class)7.selectAll();
4. Prefer Path Queries Over Manual Joins
1// Good - simple and efficient2Query.from(Article.class)3.where("author/name = ?", "John Doe")4.selectAll();56// Avoid - more complex7Author author = Query.from(Author.class)8.where("name = ?", "John Doe")9.first();10Query.from(Article.class)11.where("author = ?", author)12.selectAll();
5. Initialize Collections in Getters
1// Good2public List<String> getTags() {3if (tags == null) {4tags = new ArrayList<>();5}6return tags;7}89// Bad - can return null10public List<String> getTags() {11return tags;12}