Skip to content
Jon P Smith edited this page Oct 19, 2020 · 13 revisions

The update of an entity in the database uses CrudServices's UpdateAndSave method. In web applications this has a typical two-stage update consisting of

  1. ReadSingle<EntityOrDto>(key) to show the user the current state, some of which will be editable.
  2. UpdateAndSave(Data) or UpdateAndSave(JsonPatchDocument) to update the entity.

NOTE: The UpdateAndSave method uses EF Core Tracking Snapshots for updates, not the Update method. This means it produces efficient database updates.

Updates of DDD-styled entity classes

In a DDD-styled class you will have a series of methods to update the data inside the class. There are two types of updates.

The example methods are taken from the Book class in this repo.

Updates to properties in the class

These are fairly simple, often taking the data provided to the method and updating the properties.

  • UpdatePublishedOn method - updates book's PublishedOn property.
  • AddPromotion method- adds/updates a price promotion on a book. This returns IStatusGeneric because it contains some error checks.
  • RemovePromotion - removes a price promotion on a book (See note 4).

Updates to relationships

These are more complex because you often need the relationship loaded before you can update it. You have two options:

Use IncludeThen attribute to load the relationship before calling the method - see

  • AddReviewWithInclude method - adds a new review to the book.
  • RemoveReviewWithInclude method - removes a review from the book.

See IncludeThen Feature page for more information on how to use IncludeThen attribute on your DTO.

Add DbContext or YourDbContext as a parameter in your method

Here you have access to the database via the context parameter that EfCore.GenericServices will provide. This allows full control over how you access the database (but you mustn't call SaveChanges!). Here are some examples.

  • AddReview method - adds a new review to the book.
  • RemoveReview method - removes a review from the book. The RazorAppPage application contains multiple examples of the use of the UpdateAndSave method:

Updates of standard-styled entity classes

Example of JSON Patch

See article Pragmatic Domain-Driven Design: supporting JSON Patch in Entity Framework Core for more on this.

Potential security issue with standard-styled entity classes
For standard-styled entity classes, or any updates done by AutoMapper it is really important to use the [ReadOnly(true)] attribute to mark those properties you DON'T want updated in the database (see this doc).
Otherwise you have a vulnerability, as the values that you showed but didn't expect to change, like the title, could be changed by someone hacking the HTTP request.

NOTE: You do not need [ReadOnly(true)] when using DDD-styled entity classes.

Notes

  1. If the entity class has any methods that return void or IStatusGeneric then it will look at these to do the update. Otherwise it tries to use AutoMapper.
  2. If there are methods in the entity it will try to match the DTOs name, (minus this set of possible DTO endings: "Dto", "VM", or "ViewModel" ignoring case). If there is a match it will set this as the default method to use.
  3. You can state exactly what type/name of method/AutoMapper you want to use, by providing a second parameter to the command, e.g. _service.UpdateAndSave(Data, "UpdatePublishedOn"). This is useful if there are multiple methods that will match the DTO non-read-only properties (See How GenericServices matches a DTO to a DDD method for more on this).
    The options for the second parameter are:
    • methodName - use a specific named static method, e.g. "AddPromotion"
    • methodName(n) - use a specific named static method with n parameters, e.g. "AddPromotion(3)"
    • AutoMapper - use AutoMapper's save mapping to copy the DTO into the entity
  4. For methods with no parameters, e.g. RemovePromotion() method in Book entity, you must define the method name either by:
    • Creating a DTO name that will select the method (see note 2)
    • Providing a second parameter of the call, e.g. _service.UpdateAndSave(Data, "RemovePromotion")
    • or by providing a PerDtoConfig to the DTO with the UpdateMethod overriden with the name.
Clone this wiki locally