Skip to content

Instantly share code, notes, and snippets.

@dbones
Last active March 25, 2024 21:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbones/fbaa210afeda6c599e52d20a59ce8989 to your computer and use it in GitHub Desktop.
Save dbones/fbaa210afeda6c599e52d20a59ce8989 to your computer and use it in GitHub Desktop.
Laters EF
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Common;
using Laters;
using Laters.AspNet;
using Laters.ClientProcessing;
using Laters.Data.EntityFrameworkCore;
using Laters.Minimal.Application;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
//connection to share
builder.Services.AddScoped<DbConnection>(_ => {
var connectionString = "Host=postgres;Port=5432;Database=laters;Username=application;Password=ABC123!!";
return new Npgsql.NpgsqlConnection(connectionString);
});
//applications db context
builder.Services.AddDbContext<TodoItemDbContext>((provider, options) => {
var connection = provider.GetRequiredService<DbConnection>();
options.UseNpgsql(connection);
});
builder.WebHost.ConfigureLaters((context, setup)=>
{
//reference ourself for the demo
setup.Configuration.WorkerEndpoint = "http://localhost:5056";
//setting up EF as the storage
setup.UseStorage<UseEntityFramework>(ef =>
{
//using the same connection as above
ef.ConnectionFactory = provider => provider.GetRequiredService<DbConnection>();
ef.ApplyOptions =(_, connection, options) =>
{
//injecting the connection, and setting up the migration to be in this assembly
options.UseNpgsql(connection, b=> b.MigrationsAssembly("EpicTodoList.Service"));
};
});
});
var app = builder.Build();
app.UseLaters();
app.UseMiddleware<TransactionMiddleware>();
app.MapGet("/todo-items", (TodoItemDbContext context) =>
{
var items = context.TodoItems.ToList();
return Task.FromResult(items);
});
app.MapPost("/todo-items", ([FromBody]TodoItem item, TodoItemDbContext context) =>
{
item.Id ??= Guid.NewGuid().ToString("D");
context.TodoItems.Add(item);
return Results.Created($"/todo-items/{item.Id}", item);
});
app.MapPut("/todo-items/{id}", async (
[FromBody]TodoItem item,
string id,
TodoItemDbContext context,
ISchedule schedule) =>
{
var existingItem = await context.TodoItems.FindAsync(id);
if (existingItem == null)
{
return Results.NotFound();
}
existingItem.Title = item.Title;
existingItem.Details = item.Details;
existingItem.Completed = item.Completed;
if (existingItem.Completed)
{
var removeDateTime = DateTime.UtcNow.AddMinutes(1);
schedule.ForLater(new RemoveTodoItem { Id = existingItem.Id }, removeDateTime);
}
return Results.NoContent();
});
app.MapHandler<RemoveTodoItem>(async (JobContext<RemoveTodoItem> ctx, TodoItemDbContext context) =>
{
var item = await context.TodoItems.FindAsync(ctx.Payload!.Id);
if (item != null)
{
context.TodoItems.Remove(item);
}
await Task.CompletedTask;
});
app.Run();
public class TransactionMiddleware
{
private readonly RequestDelegate _next;
public TransactionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(
HttpContext context,
TodoItemDbContext todoDbContext,
LatersDbContext latersDbContext,
DbConnection connection)
{
await _next(context);
if(connection.State != ConnectionState.Open)
{
connection.Open();
}
using var tx = connection.BeginTransaction(IsolationLevel.Serializable);
todoDbContext.Database.UseTransaction(tx);
latersDbContext.Database.UseTransaction(tx);
await todoDbContext.SaveChangesAsync();
await latersDbContext.SaveChangesAsync();
tx.Commit();
}
}
public class RemoveTodoItem
{
public string Id { get; set; } = string.Empty;
}
public class TodoItem
{
public string Id { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Details { get; set; } = string.Empty;
public bool Completed { get; set; } = false;
}
public class TodoItemDbContext : DbContext
{
public TodoItemDbContext(DbContextOptions<TodoItemDbContext> options) : base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; } = null!;
}
@dbones
Copy link
Author

dbones commented Mar 25, 2024

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Laters
dotnet add package Laters.Data.EntityFrameworkCore

dotnet ef migrations add InitialCreate --context TodoItemDbContext
dotnet ef database update --context TodoItemDbContext

dotnet ef migrations add InitialCreate --context LatersDbContext
dotnet ef database update --context LatersDbContext

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment