175 lines
7.8 KiB
Markdown
175 lines
7.8 KiB
Markdown
# Data Layer
|
|
|
|
> Part of `Nop.Plugin.Misc.FruitBankPlugin`. See `README.md` for project overview.
|
|
> For entity model see `docs/DOMAIN_MODEL.md`.
|
|
> For measurement workflows see `docs/MEASUREMENT.md`.
|
|
|
|
## DbContext Classes
|
|
|
|
### FruitBankDbContext
|
|
|
|
Inherits `MgDbContextBase` (from `Mango.Nop.Data`). Main data context for orders, shipping, partners, and files.
|
|
|
|
**Implements interfaces:** IOrderDtoDbSet, IOrderItemDtoDbSet, IPartnerDbSet, IShippingDbSet, IShippingDocumentDbSet, IShippingItemDbSet, IShippingItemPalletDbSet, IOrderItemPalletDbSet, IShippingDocumentToFilesDbSet, IFilesDbSet
|
|
|
|
**DbSet properties:**
|
|
|
|
| DbSet | Entity | Table |
|
|
|---|---|---|
|
|
| `OrderDtos` | OrderDto | Order |
|
|
| `OrderItemDtos` | OrderItemDto | OrderItem |
|
|
| `OrderItemPallets` | OrderItemPallet | fbOrderItemPallet |
|
|
| `Partners` | Partner | fbPartner |
|
|
| `Shippings` | Shipping | fbShipping |
|
|
| `ShippingDocuments` | ShippingDocument | fbShippingDocument |
|
|
| `ShippingItems` | ShippingItem | fbShippingItem |
|
|
| `ShippingItemPallets` | ShippingItemPallet | fbShippingItemPallet |
|
|
| `Files` | Files | fbFiles |
|
|
| `ShippingDocumentToFiles` | ShippingDocumentToFiles | fbShippingDocumentToFiles |
|
|
| `ProductDtos` | ProductDto | Product |
|
|
| `GenericAttributeDtos` | GenericAttributeDto | GenericAttribute |
|
|
| `StockQuantityHistoryDtos` | StockQuantityHistoryDto | StockQuantityHistory |
|
|
| `Customers` | Customer | Customer |
|
|
| `CustomerRoles` | CustomerRole | CustomerRole |
|
|
|
|
**Key methods:**
|
|
|
|
| Method | Purpose |
|
|
|---|---|
|
|
| `AddShippingItemAsync()` | Creates item, copies `IsMeasurable` from ProductDto |
|
|
| `UpdateShippingItemAsync()` | Complex: updates measuring values, handles stock/weight changes, manages product transitions |
|
|
| `SetupShippingItemMeasuringValues()` | Recalculates totals from child pallets |
|
|
| `AddShippingItemPalletAsync()` / `UpdateShippingItemPalletAsync()` | Pallet CRUD with cascade to parent ShippingItem |
|
|
| `StartMeasuringAsync()` | Sets MeasurementOwnerId GenericAttribute, updates order status |
|
|
| `SetOrderStatusToCompleteAsync()` | Validates pallets, updates stock, sets RevisorId, publishes event |
|
|
| `DeleteOrderItemConstraintsAsync()` | Cleanup when order items deleted |
|
|
| `UpdateStockQuantityAndWeightAsync()` | Updates Product.StockQuantity + NetWeight, creates history entry |
|
|
| `DeleteShippingSafeAsync()` | Transactional cascade delete of shipping + children |
|
|
| `DeleteShippingDocumentSafeAsync()` | Transactional cascade delete of document + children |
|
|
| `GetCustomersBySystemRoleName()` | LINQ query for role-based customer lookup |
|
|
|
|
All state-changing operations wrapped in `TransactionSafeAsync()` for ACID compliance.
|
|
|
|
### StockTakingDbContext
|
|
|
|
Inherits `MgDbContextBase`. Dedicated context for inventory sessions.
|
|
|
|
**DbSet properties:**
|
|
|
|
| DbSet | Entity |
|
|
|---|---|
|
|
| `ProductDtos` | ProductDto |
|
|
| `OrderItemDtos` | OrderItemDto |
|
|
| `StockTakings` | StockTaking |
|
|
| `StockTakingItems` | StockTakingItem |
|
|
| `StockTakingItemPallets` | StockTakingItemPallet |
|
|
| `StockQuantityHistories` | StockQuantityHistory |
|
|
| `GenericAttributes` | GenericAttribute |
|
|
|
|
**Key methods:**
|
|
|
|
| Method | Purpose |
|
|
|---|---|
|
|
| `CloseStockTaking()` | Validates all measured, updates stock/weight per item, marks closed |
|
|
| `AddStockTakingItemPallet()` / `UpdateStockTakingItemPallet()` | Pallet CRUD with measured values refresh |
|
|
| `RefreshStockTakingItemMeasuredValuesFromPallets()` | Sums quantities/weights from pallets |
|
|
|
|
## DbTable Repositories
|
|
|
|
Each entity has a `*DbTable` class inheriting `MgDbTableBase<T>` (from `Mango.Nop.Data`). Located in `Domains/DataLayer/`.
|
|
|
|
### ShippingDbTable
|
|
|
|
| Method | Purpose |
|
|
|---|---|
|
|
| `GetAll()` | All shippings ordered by ShippingDate |
|
|
| `GetAll(bool loadRelations)` | Eager loads full graph: Documents → Items → Pallets + Pallet type + ProductDto + GenericAttributes |
|
|
| `GetAllNotMeasured()` | Filters for incomplete/recent shipments |
|
|
| `GetByIdAsync(bool loadRelations)` | Single with optional eager loading |
|
|
| `OnUpdate()` | Hook: sets `MeasuredDate` when `IsAllMeasured` becomes true |
|
|
|
|
### OrderDtoDbTable
|
|
|
|
| Method | Purpose |
|
|
|---|---|
|
|
| `GetAll(bool loadRelations)` | Eager loads: GenericAttributes, Customer, OrderNotes, OrderItemDtos (with ProductDto, GenericAttributes, OrderItemPallets) |
|
|
| `GetByIdAsync(bool loadRelations)` | Single order with optional relations |
|
|
| `GetAllByOrderStatus()` | Status-filtered query |
|
|
| `GetAllForMeasuring(DateTime fromDate)` | Unpaid, not cancelled, with DateOfReceipt >= fromDate |
|
|
| `GetAllByProductId()` / `GetAllByProductIds()` | Product-filtered queries |
|
|
| `GetAllByIds()` | Batch retrieval |
|
|
|
|
### Other DbTable classes
|
|
|
|
| Class | Entity | Key behaviors |
|
|
|---|---|---|
|
|
| `ProductDtoDbTable` | ProductDto | GetAll with GenericAttributes |
|
|
| `PartnerDbTable` | Partner | Standard CRUD |
|
|
| `ShippingDocumentDbTable` | ShippingDocument | GetAll with items, files, partner |
|
|
| `ShippingItemDbTable` | ShippingItem | GetAll with pallets |
|
|
| `ShippingItemPalletDbTable` | ShippingItemPallet | Standard CRUD |
|
|
| `OrderItemDtoDbTable` | OrderItemDto | GetAll with pallets, product |
|
|
| `OrderItemPalletDbTable` | OrderItemPallet | Standard CRUD |
|
|
| `FilesDbTable` | Files | Standard CRUD |
|
|
| `ShippingDocumentToFilesDbTable` | ShippingDocumentToFiles | Standard CRUD |
|
|
| `StockTakingDbTable` | StockTaking | GetAll with items, pallets |
|
|
| `StockTakingItemDbTable` | StockTakingItem | GetAll with pallets |
|
|
| `StockTakingItemPalletDbTable` | StockTakingItemPallet | Standard CRUD |
|
|
| `StockQuantityHistoryDtoDbTable` | StockQuantityHistoryDto | Filtered by date range |
|
|
|
|
## Repository Interfaces
|
|
|
|
Located in `Domains/DataLayer/Interfaces/`. Each interface (e.g., `IShippingDbSet`, `IOrderDtoDbSet`) declares the DbSet property that the DbContext must implement. This allows DbTable classes to accept any context that provides the required DbSet.
|
|
|
|
## Entity Mapping
|
|
|
|
- `Mapping/Builders/PluginBuilder.cs` — EF Core Fluent API entity configuration for plugin-owned tables (fb* prefix)
|
|
- `Mapping/NameCompatibility.cs` — Table name mapping for nopCommerce compatibility
|
|
- `Migrations/SchemaMigration.cs` — FluentMigrator schema setup for `CustomTable` base entity
|
|
|
|
## FruitBankEventConsumer
|
|
|
|
Located in `Domains/EventConsumers/`. Extends `MgEventConsumerBase` (from `Mango.Nop.Services`). Handles entity lifecycle events for cascading updates.
|
|
|
|
**Product events:**
|
|
|
|
| Event | Action |
|
|
|---|---|
|
|
| `EntityInsertedEvent<Product>` | Saves custom attributes (IsMeasurable, NetWeight, Tare, AverageWeight, AverageWeightTreshold, IncomingQuantity) |
|
|
| `EntityUpdatedEvent<Product>` | Updates custom attributes, syncs IsMeasurable/Tare changes to existing ShippingItems |
|
|
|
|
**Shipping cascade events:**
|
|
|
|
| Event | Action |
|
|
|---|---|
|
|
| `EntityDeletedEvent<ShippingItemPallet>` | Refreshes parent ShippingItem measuring values |
|
|
| `EntityInsertedEvent/UpdatedEvent<ShippingItem>` | Rechecks ShippingDocument.IsAllMeasured |
|
|
| `EntityInsertedEvent/UpdatedEvent<ShippingDocument>` | Rechecks Shipping.IsAllMeasured |
|
|
| `EntityDeletedEvent<Shipping>` | Cascade deletes child documents |
|
|
| `EntityDeletedEvent<ShippingDocument>` | Cascade deletes child items |
|
|
| `EntityDeletedEvent<ShippingItem>` | Cascade deletes child pallets |
|
|
|
|
**Order events:**
|
|
|
|
| Event | Action |
|
|
|---|---|
|
|
| `EntityDeletedEvent<OrderItem>` | Cleanup via `MeasurementService.DeleteOrderItemConstraintsAsync()` |
|
|
| `EntityInsertedEvent/UpdatedEvent<OrderItem>` | Post-process via `MeasurementService.OrderItemInsertedOrUpdatedPostProcess()` |
|
|
|
|
## Eager Loading Pattern
|
|
|
|
DbTable `GetAll(bool loadRelations = true)` uses `LoadWith()` chains to eagerly load entity graphs. Example for OrderDtoDbTable:
|
|
|
|
```
|
|
OrderDto
|
|
→ GenericAttributes
|
|
→ Customer
|
|
→ OrderNotes
|
|
→ OrderItemDtos
|
|
→ ProductDto → GenericAttributes
|
|
→ GenericAttributes
|
|
→ OrderItemPallets
|
|
```
|
|
|
|
This avoids N+1 queries when transferring full entity graphs to FruitBankHybridApp via SignalR.
|