Integrate deep-dive content into API docs and expand mapping

This commit is contained in:
root
2026-02-26 08:06:56 +01:00
parent 2c25e78bef
commit b628348af8
7 changed files with 267 additions and 230 deletions

View File

@@ -1,8 +1,26 @@
# Mapping and Entities
DynamORM supports attribute-driven mapping and entity lifecycle helpers.
DynamORM mapping is a core feature, not just a convenience layer.
## Mapping Attributes
It controls:
- class-to-table resolution
- property-to-column resolution
- key semantics for updates/deletes
- schema override details (`DbType`, size, precision, scale)
- lifecycle operations (`Insert`, `Update`, `Delete`, `Refresh`, `Save`)
## Mapping Resolution Model
At runtime, `DynamicMapperCache` builds and caches `DynamicTypeMap` for each type.
`DynamicTypeMap` is used by:
- typed query execution (`Execute<T>()`)
- dynamic projection to classes
- entity lifecycle operations in `DynamicEntityBase`
- procedure result mapping
- validation (`ValidateObject`)
## `TableAttribute`
@@ -14,9 +32,11 @@ public class User
}
```
Fields:
- `Name`: table name override.
- `Owner`: schema/owner segment.
- `Override`: prefer attribute schema info over provider schema.
- `Override`: prefer attribute schema over database schema (important when provider schema is limited).
## `ColumnAttribute`
@@ -28,6 +48,9 @@ public class User
[Column("email")]
public string Email { get; set; }
[Column("created_at", false, DbType.DateTime)]
public DateTime CreatedAt { get; set; }
}
```
@@ -39,13 +62,40 @@ Important flags:
- `IsNoUpdate`
- `Type`, `Size`, `Precision`, `Scale`
## Ignore Fields
These influence generated parameters and update/insert behavior.
Use `IgnoreAttribute` to skip properties in mapper-driven workflows.
## Advanced Mapping Example
## Validation
```csharp
[Table(Name = "users", Override = true)]
public class UserEntity : DynamicEntityBase
{
[Column("id", true, DbType.Int32)]
public int Id { get; set; }
`RequiredAttribute` can define value rules.
[Column("code", false, DbType.String, 32)]
public string Code { get; set; }
[Column("email", false, DbType.String, 256)]
public string Email { get; set; }
[Column("created_at", false, DbType.DateTime)]
[Ignore]
public DateTime CreatedAtInternal { get; set; }
}
```
## Ignore and Partial Mapping
Use `[Ignore]` when:
- property is computed locally
- property is not persisted
- property should not participate in auto update/insert
## Validation (`RequiredAttribute`)
`RequiredAttribute` can enforce range and null/empty semantics.
```csharp
public class Profile
@@ -63,33 +113,65 @@ var issues = DynamicMapperCache.GetMapper<Profile>().ValidateObject(profile);
Validation scenarios are verified in `DynamORM.Tests/Helpers/Validation/ObjectValidationTest.cs`.
## `DynamicEntityBase`
## `DynamicEntityBase` Lifecycle
`DynamicEntityBase` tracks state and changed fields.
State-driven `Save(db)` behavior:
- `New` => `Insert`
- `Existing` + modified => `Update`
- `ToBeDeleted` => `Delete`
- `Deleted` => throws for write operations
- `Unknown` => throws (explicit state needed)
Example entity with property change tracking:
```csharp
public class UserEntity : DynamicEntityBase
{
private string _first;
[Column("id", true)]
public int Id { get; set; }
[Column("first")]
public string First { get; set; }
public string First
{
get => _first;
set
{
OnPropertyChanging(nameof(First), _first, value);
_first = value;
}
}
}
```
Available behaviors:
Typical flow:
- `Validate()`
- `Insert(db)`
- `Update(db)`
- `Delete(db)`
- `Refresh(db)`
- `Save(db)` driven by `DynamicEntityState`
```csharp
var user = db.From<UserEntity>()
.Where(x => x.id == 19)
.Execute<UserEntity>()
.First();
## Repository Base
user.SetDynamicEntityState(DynamicEntityState.Existing);
user.First = "Yuri";
user.Save(db); // updates only changed fields when possible
```
`DynamicRepositoryBase<T>` provides common operations:
## Refresh and Key Requirements
`Refresh(db)`, `Update(db)`, and `Delete(db)` rely on key columns.
If no key mapping is available, entity update/delete operations throw.
Always map at least one key (`IsKey = true`) for mutable entities.
## Repository Layer (`DynamicRepositoryBase<T>`)
`DynamicRepositoryBase<T>` provides:
- `GetAll()`
- `GetByQuery(...)`
@@ -98,4 +180,11 @@ Available behaviors:
- `Delete(...)`
- `Save(...)`
It ensures query/table compatibility for `T` unless explicitly bypassed.
It validates that query tables match mapped type `T` before executing typed enumeration.
## Practical Recommendations
- Always define keys explicitly in mapped models.
- Use `Override = true` when provider schema metadata is weak or inconsistent.
- Keep entities focused on persistence fields; use `[Ignore]` for non-persisted members.
- Use validation on boundary objects before persisting.