Storage Operations with EF Core
Just know that Wolverine completely supports the concept of Storage Operations for EF Core.
Assuming you have an EF Core DbContext
type like this registered in your system:
public class TodoDbContext : DbContext
{
public TodoDbContext(DbContextOptions<TodoDbContext> options) : base(options)
{
}
public DbSet<Todo> Todos { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Todo>(map =>
{
map.ToTable("todos", "todo_app");
map.HasKey(x => x.Id);
map.Property(x => x.Name);
map.Property(x => x.IsComplete).HasColumnName("is_complete");
});
}
}
You can use storage operations in Wolverine message handlers or HTTP endpoints like these samples from the Wolverine test suite:
public static class TodoHandler
{
public static Insert<Todo> Handle(CreateTodo command) => Storage.Insert(new Todo
{
Id = command.Id,
Name = command.Name
});
public static Store<Todo> Handle(CreateTodo2 command) => Storage.Store(new Todo
{
Id = command.Id,
Name = command.Name
});
// Use "Id" as the default member
public static Update<Todo> Handle(
// The first argument is always the incoming message
RenameTodo command,
// By using this attribute, we're telling Wolverine
// to load the Todo entity from the configured
// persistence of the app using a member on the
// incoming message type
[Entity] Todo todo)
{
// Do your actual business logic
todo.Name = command.Name;
// Tell Wolverine that you want this entity
// updated in persistence
return Storage.Update(todo);
}
// Use "TodoId" as the default member
public static Update<Todo> Handle(RenameTodo2 command, [Entity] Todo todo)
{
todo.Name = command.Name;
return Storage.Update(todo);
}
// Use the explicit member
public static Update<Todo> Handle(RenameTodo3 command, [Entity("Identity")] Todo todo)
{
todo.Name = command.Name;
return Storage.Update(todo);
}
public static Delete<Todo> Handle(DeleteTodo command, [Entity("Identity")] Todo todo)
{
return Storage.Delete(todo);
}
public static IStorageAction<Todo> Handle(AlterTodo command, [Entity("Identity")] Todo todo)
{
switch (command.Action)
{
case StorageAction.Delete:
return Storage.Delete(todo);
case StorageAction.Update:
todo.Name = command.Name;
return Storage.Update(todo);
case StorageAction.Store:
todo.Name = command.Name;
return Storage.Store(todo);
default:
return Storage.Nothing<Todo>();
}
}
public static IStorageAction<Todo> Handle(MaybeInsertTodo command)
{
if (command.ShouldInsert)
{
return Storage.Insert(new Todo { Id = command.Id, Name = command.Name });
}
return Storage.Nothing<Todo>();
}
public static Insert<Todo>? Handle(ReturnNullInsert command) => null;
public static IStorageAction<Todo>? Handle(ReturnNullStorageAction command) => null;
public static IStorageAction<Todo> Handle(CompleteTodo command, [Entity] Todo todo)
{
if (todo == null) throw new ArgumentNullException(nameof(todo));
todo.IsComplete = true;
return Storage.Update(todo);
}
public static IStorageAction<Todo> Handle(MaybeCompleteTodo command, [Entity(Required = false)] Todo? todo)
{
if (todo == null) return Storage.Nothing<Todo>();
todo.IsComplete = true;
return Storage.Update(todo);
}
}
[Entity]
Wolverine also supports the usage of the [Entity]
attribute to load entity data by its identity with EF Core. As you'd expect, Wolverine can "find" the right EF Core DbContext
type for the entity type through IoC service registrations.