我正在创建一个应用程序,它有多个客户端,可以更新相同的数据,所以我计划使用这种方法更新水果。将它们保存到数据库中,然后使用SignalR更新所有其他客户端。我正在努力设计代码以避免并发问题,所以我从
here
我想知道如何将事务与这段代码结合起来(我已经尝试过,但不确定它是否正确或必要)?或者因为它是为了处理并发性而设计的,我甚至需要事务吗?
为了创建并发问题,我将断点设置为
dbContext.SaveChanges();
并更新数据库中的数据。
app.MapPut("UpdateFruits", async (string message, IHubContext<ChatHub> context, DatabaseContext dbContext) =>
{
//message(Param) = { "ID":"2","DisplayName":"Fruit","Leaf":null,"State":"Chopped"}
using var transaction = dbContext.Database.BeginTransaction();
try
{
// Fetch a person from database and change phone number
var fruit = dbContext.Set<Fruit>().Single(p => p.ID == 1);
fruit.State = State.Chopped;
fruit.DisplayName = "test";
var saved = false;
while (!saved)
{
try
{
// Attempt to save changes to the database
dbContext.SaveChanges();
saved = true;
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is Fruit)
{
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
foreach (var property in proposedValues.Properties)
{
var proposedValue = proposedValues[property];
var databaseValue = databaseValues[property];
// TODO: decide which value should be written to database
// proposedValues[property] = <value to be saved>;
}
// Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);
}
else
{
throw new NotSupportedException(
"Don't know how to handle concurrency conflicts for "
+ entry.Metadata.Name);
}
}
}
}
transaction.Commit();
var jsonString = JsonConvert.SerializeObject(fruit);
await context.Clients.All.SendAsync("ReceiveMessage", "FromServer", jsonString);
}
catch (Exception)
{
transaction.Rollback();
}
return Results.NoContent();
});
型号:
public class Fruit
{
public int ID { get; set; }
public string DisplayName { get; set; } = String.Empty;
public List<Leaf>? Leaf{ get; set; }
}
public class Leaf
{
public int ID { get; set; }
public string DisplayName { get; set; } = String.Empty;
public List<Vein>? Vein{ get; set; }
}
public class Vein
{
public int ID { get; set; }
public string DisplayName { get; set; } = String.Empty;
}
DBContext:
using EAS.API.PropertyManagement.Entities;
using GFX.Suite.API.GFX.Entities;
using Microsoft.EntityFrameworkCore;
using System.Collections;
namespace EAS.API.PropertyManagement.Core;
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions options) : base(options)
{
}
Random rnd = new Random();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Fruit>(builder =>
{
builder.ToTable("Fruit");
//builder.HasMany(c => c.Leaf)
//.WithOne()
//.HasForeignKey(f => f.LeafID);
//var rendertypes = Enumerable
// .Range(1, 5)
// .Select(x => new Fruit
// {
// ID = x,
// DisplayName = $"Fruits {x}",
// })
// .ToList();
//builder.HasData(rendertypes);
});
modelBuilder.Entity<Leaf>(builder =>
{
builder.ToTable("Leaf");
//var properties = Enumerable
// .Range(1, 5)
// .Select(x => new Leaf
// {
// ID = x,
// DisplayName = $"Leaf {x}",
// })
// .ToList();
//builder.HasData(properties);
});
modelBuilder.Entity<Vein>(builder =>
{
builder.ToTable("Vein");
//var properties = Enumerable
// .Range(1, 5)
// .Select(x => new Vein
// {
// ID = x,
// DisplayName = $"Vein {x}",
// })
// .ToList();
//builder.HasData(properties);
});
}
}