Modification

The Stem base class contains some virtual methods that are called at certain stages in a request.

OnSaving and OnSaved

Saving changes happens in the background with a single SaveChanges() call to your repository. Stems provide ways to execute custom code before and after that call.

The OnSavingAsync method is executed before this call. Any exceptions thrown in that method will be returned to the client and the entity is not saved.

The OnSavedAsync method is executed after the changes have been committed to the repository. Any modifications to the entity object made here won't be saved.

public class ArtistsStem : Stem<Artist>
{
    // Contructor and properties omitted for brevity.

    protected override async Task OnSavingAsync(Artist artist)
    {
        artist.LastModified = DateTime.UtcNow;
    }

    protected override async Task OnSavedAsync(Artist artist)
    {
        await _eventPublisher.PublishAsync(new ArtistModifiedEvent
        {
            ArtistId = artist.Id
        });
    }
}

OnCreating

The OnCreating method is called just after a new entity is instantiated.

By default, this is called when a client performs a POST request to the collection.

public class ArtistsStem : Stem<Artist>
{
    // Contructor and properties omitted for brevity.

    public override void OnCreating(Artist newArtist)
    {
        newArtist.CreatedDate = DateTime.UtcNow,
        newArtist.CreatedByUserName = User.Identity.Name
    }
}

OnUpdating

The OnUpdating method is called just before an updated entity is saved to the database.

public class ArtistsStem : Stem<Artist>
{
    // Contructor and properties omitted for brevity.

    public override void OnUpdating(Artist artist)
    {
        newArtist.ModifiedDate = DateTime.UtcNow,
        newArtist.ModifiedByUserName = User.Identity.Name
    }
}

MarkDeleted

The MarkDeleted method is called when the entity is deleted. As with OnCreating, the deletion is not committed to the repository until OnSavedAsync is called.

Overriding this method allows you to perform a "soft delete" where the entity remains in the database. In this case, the method should return true to indicate that it has handled the deletion.

To ensure these entities don't appear in your API queries after being marked as deleted, you could override PermissionExpression to indicate that deleted items are not readable.

public class ArtistsStem : Stem<Artist>
{
    // Contructor and properties omitted for brevity.

    protected override bool MarkDeleted(Artist artist)
    {
        artist.IsDeleted = true;
        return true;
    }

    protected override Expression<Func<Artist, ItemPermission>> PermissionExpression
    {
        get
        {
            return a => a.IsDeleted
                ? ItemPermission.None
                : ItemPermission.ReadWriteDelete;
        }
    }
}