feat: Lazy DAO fields#2713
Conversation
| * Maps each table to a set of its lazy columns. | ||
| * This allows EntityClass to efficiently filter out lazy columns for its specific table. | ||
| */ | ||
| internal val lazyColumns = mutableMapOf<Table, MutableSet<Column<*>>>() |
There was a problem hiding this comment.
In terms of API I didn't want to extend DSL layer, because it doesn't look like DSL need lazy column, so I wanted the method like lazy() exists only in Entities, but in this case it's a bit complicated to track which fields are lazy and which are not, because columns in DAO are delegates.
So I stopped at the variant of creating global cache for lazy columns assuming that in general it's not a big set. Every column is registered in the moment of call lazy().
Initially I hoped that in the moment of call lazy() the column could be stored inside entity, but at that moment it's not initialized yet.
vnikolova
left a comment
There was a problem hiding this comment.
Docs look good, thanks for the addition! 👍
Suggested some small edits below.
| <chapter id="lazy-fields" title="Lazy fields"> | ||
| <p> | ||
| By default, all entity properties are loaded immediately when an entity is retrieved from the database. | ||
| However, for large columns like BLOBs or TEXT fields, or for rarely accessed data, this can negatively |
There was a problem hiding this comment.
| However, for large columns like BLOBs or TEXT fields, or for rarely accessed data, this can negatively | |
| However, for large columns like BLOB or TEXT fields, or for rarely accessed data, this behavior can negatively |
| <p> | ||
| Exposed provides the | ||
| <a href="%BASE_API_URL%/exposed-dao/org.jetbrains.exposed.dao/-entity/lazy.html"><code>.lazy()</code></a> | ||
| modifier to mark columns as lazy-loaded. Lazy fields are: |
There was a problem hiding this comment.
| modifier to mark columns as lazy-loaded. Lazy fields are: | |
| modifier, which allows you to mark columns as lazy-loaded. Lazy fields are: |
| modifier to mark columns as lazy-loaded. Lazy fields are: | ||
| </p> | ||
| <list> | ||
| <li>Excluded from the default entity query</li> |
There was a problem hiding this comment.
| <li>Excluded from the default entity query</li> | |
| <li>Excluded from the default entity query.</li> |
| </p> | ||
| <list> | ||
| <li>Excluded from the default entity query</li> | ||
| <li>Loaded on-demand when first accessed</li> |
There was a problem hiding this comment.
| <li>Loaded on-demand when first accessed</li> | |
| <li>Loaded on-demand when first accessed.</li> |
| <list> | ||
| <li>Excluded from the default entity query</li> | ||
| <li>Loaded on-demand when first accessed</li> | ||
| <li>Cached after the first access to avoid redundant queries</li> |
There was a problem hiding this comment.
| <li>Cached after the first access to avoid redundant queries</li> | |
| <li>Cached after the first access to avoid redundant queries.</li> |
| * | ||
| * On first access: | ||
| * 1. Checks for active transaction | ||
| * 2. Flushes entity if it has pending writes |
There was a problem hiding this comment.
| * 2. Flushes entity if it has pending writes | |
| * 2. Flushes the entity if it has pending writes. |
| * On first access: | ||
| * 1. Checks for active transaction | ||
| * 2. Flushes entity if it has pending writes | ||
| * 3. Loads this lazy column value from the database |
There was a problem hiding this comment.
| * 3. Loads this lazy column value from the database | |
| * 3. Loads the lazy column value from the database. |
| * 1. Checks for active transaction | ||
| * 2. Flushes entity if it has pending writes | ||
| * 3. Loads this lazy column value from the database | ||
| * 4. Caches the lazy value for subsequent accesses |
There was a problem hiding this comment.
| * 4. Caches the lazy value for subsequent accesses | |
| * 4. Caches the lazy column value for subsequent accesses. |
| /** | ||
| * Sets the value of this lazy field for the given entity. | ||
| * | ||
| * The value is stored in the entity's write values and will be persisted on flush. |
There was a problem hiding this comment.
| * The value is stored in the entity's write values and will be persisted on flush. | |
| * The value is stored in the entity's write values and is persisted on flush. |
| import org.jetbrains.exposed.v1.core.Column | ||
|
|
||
| /** | ||
| * An exception that provides information about a lazy [column] that was accessed |
There was a problem hiding this comment.
| * An exception that provides information about a lazy [column] that was accessed | |
| * An exception that provides information about a lazy [column] accessed |
Description
Summary of the change: Added lazy loading support for DAO entity fields, allowing developers to mark large or rarely-accessed columns (e.g., BLOB, TEXT) as lazy-loaded to improve query performance and reduce memory usage.
What:
LazyEntityFieldclass that implements property delegation for lazy-loaded columns.lazy()extension function to mark entity properties as lazy-loadedlazyFieldCache) in theEntityclass to store lazy field valuesHow:
getValue()/setValue()operators for lazy property delegation. Maintains a global registry of lazy columns per table. On first access, executes a targeted SELECT query for that specific column and caches the result.lazyFieldCacheHashMap to store lazy field values independently fromreadValues. ModifiedstoreWrittenValues()to cache lazy fields during flush, preventing unnecessary database queries. Addedrefresh()support to clear lazy field cache.Type of Change
Please mark the relevant options with an "X":
Affected databases:
Related Issues
Can DAO API support conditional retrieve some columns?