提问人:Ali.M Eghbaldar 提问时间:10/30/2023 更新时间:10/31/2023 访问量:31
如何通过 DbContext 访问门面接口?
How to access a facade interface through DbContext?
问:
我有一个棘手的问题,如果有人能帮助我解决这个问题,那就太好了。 有一个用于修改实体的 facade 类,我想在发生操作时获取用户的操作并将其存储在 UsersActionsLog 实体中:
public class UsersActionsLog
{
[Key]
public long Id { get; set; }
public long UserId { get; set; }
public string Entity { get; set; }
public string? PrimaryKeyValue { get; set; }
public string PropertyName { get; set; }
public string OldValue { get; set; }
public string NewValue { get; set; }
public string Action { get; set; } // [0]=Added [1]=Modified [2]=Deleted
public bool Successful { get; set; } // [false]= failed [true]=successful
public DateTime Date { get; set; } = DateTime.Now;
}
我正在使用 facade 模式来执行代码。 我的服务:
public class RequestPostUserActionLogServiceDto
{
public long UserId { get; set; }
public string Entity { get; set; }
public string? PrimaryKeyValue { get; set; }
public string PropertyName { get; set; }
public string OldValue { get; set; }
public string NewValue { get; set; }
public string Action { get; set; } // [0]=Added [1]=Modified [2]=Deleted
public bool Successful { get; set; } // [false]= failed [true]=successful
}
public interface IPostUserActionLogService
{
bool Execute(RequestPostUserActionLogServiceDto req);
}
public class PostUserActionLogService: IPostUserActionLogService
{
private readonly IDataBaseContext _context;
public PostUserActionLogService(IDataBaseContext context)
{
_context = context;
}
public bool Execute(RequestPostUserActionLogServiceDto req)
{
return true;
}
}
我的外表:
public class UserActionsLogFacade: IUserActionLogFacade
{
private readonly IDataBaseContext _context;
public UserActionsLogFacade(IDataBaseContext context)
{
_context = context;
}
///////////////////////////////////// PostUserActionLogService
private PostUserActionLogService _postUserActionLogService;
public PostUserActionLogService PostUserActionLogService
{
get { return _postUserActionLogService = _postUserActionLogService ?? new PostUserActionLogService(_context); }
}
}
和:
public interface IUserActionLogFacade
{
public PostUserActionLogService PostUserActionLogService { get;}
}
我正在尝试在“DataBaseContext”中注入“ISerActionLogFacade”,但我遇到了一个错误 [检测到类型服务的循环依赖关系] 在此处输入图像描述
public class DataBaseContext : DbContext, IDataBaseContext
{
private IUserActionLogFacade _userActionLogFacade;
public DataBaseContext(DbContextOptions option, IUserActionLogFacade userActionLogFacade) : base(option)
{
_userActionLogFacade = userActionLogFacade;
}
// Tables
public DbSet<Users> Users { get; set; } // Users Table
public DbSet<Roles> Roles { get; set; } // Roles Table
public DbSet<UsersInRoles> UsersInRoles { get; set; } // UsersInRoles Table
public DbSet<UsersActionsLog> UsersActionsLog { get; set; } // UsersActionsLog Table
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//> FLuent API of Entity Configurations
//---- Users
modelBuilder.ApplyConfiguration(new UsersConfigurations());
//---- ROles
modelBuilder.ApplyConfiguration(new RolesConfigurations());
//< End
}
public override int SaveChanges()
{
var modifiedEntries = ChangeTracker.Entries()
.Where(
e =>
e.State == EntityState.Modified ||
e.State == EntityState.Added ||
e.State == EntityState.Deleted
);
foreach (var entry in modifiedEntries)
{
var entityType = entry.Context.Model.FindEntityType(entry.Entity.GetType());
var inserted = entityType.FindProperty("InsertDate");
var updated = entityType.FindProperty("UpdateDate");
var deleted = entityType.FindProperty("DeleteDate");
switch (entry.State)
{
case EntityState.Added:
if (inserted != null) entry.Property("InsertDate").CurrentValue = DateTime.Now;
break;
case EntityState.Modified:
if (updated != null) entry.Property("UpdateDate").CurrentValue = DateTime.Now;
break;
case EntityState.Deleted:
if (deleted != null) entry.Property("DeleteDate").CurrentValue = DateTime.Now;
entry.State = EntityState.Modified;
break;
}
_userActionLogFacade.PostUserActionLogService.Execute( new RequestPostUserActionLogServiceDto
{
Entity = entry.Entity.GetType().Name, //entityName
Action = "",
NewValue = "",
OldValue = "",
PrimaryKeyValue = "1",
PropertyName = "",
Successful = true,
UserId = 1,
});
}
return base.SaveChanges();
}
}
当然,我看到了这个问题:我看到了这个问题:DbContext Override SaveChanges 没有触发,但问题是,基于该问题,应答者直接解决了问题。我的意思是,由于 CLEAN ARCHITATURE 结构,我们不能直接在 PERSISTENCE 层中使用 DOMIAN 层。 那么,如何在 OVERRIED SAVECHANGE() 方法中注入 Facade 并使用其服务呢?
答:
当涉及到审计和错误记录到数据库之类的事情时,我使用的解决方案是有界的 DbContext。基本上,对于您的审计外观,不要使用 DataBaseContext,而是创建类似 RequestActionDbContext 的东西,它只定义这个 RequestAction 实体,并被注入到 DataBaseContext 中,以便在截获的 SaveChanges() 上调用。这避免了循环依赖项问题,并确保使用 SaveChanges() 保存 RequestAction 不会触发无限递归堆栈溢出。
这种方法的缺点是,保存被跟踪的实体和保存审核记录这两个操作是独立的,因此如果一个操作失败,另一个操作不会回滚。因此,如果这很重要,那么它需要手动协调。通常,我会在 SaveChanges() 期间按照正常情况设置立面 DTO,然后将它们提交到 立面(在调用后使用 RequestActionDbContext 编写:base.SaveChanges()
var result = base.SaveChanges();
try
{
_userActionLogFacade.PostUserActionLogService.Execute(requestActionDto);
}
catch (Exception ex)
{
// Log exception... Save succeeded but audit failed...
}
return result;
这并不完美,但 IMO 涵盖了 99.95%。如果审计电话失败,则发生了严重或怪异的事情,我想手动调查和处理这种情况。
评论