【问题标题】:Dependency Injection and Generic Windows Forms C # Repository依赖注入和通用 Windows 窗体 C# 存储库
【发布时间】:2021-01-02 18:19:29
【问题描述】:

我有一个 Windows 窗体应用程序,我正在尝试对某些服务使用依赖注入,所以我最初在 Program.cs 中进行了以下配置我注册了这些服务:

static class Program
{
    [STAThread]
    static void Main()
    {
        
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        var services = new ServiceCollection();
        ConfigureServices(services);

        using (ServiceProvider serviceProvider = services.BuildServiceProvider())
        {
            var mainForm = serviceProvider.GetRequiredService<SelecionarEmpresa>();
            Application.Run(mainForm);
        }
    }

    private static void ConfigureServices(ServiceCollection services)
    {

        services.AddDbContext<AnalistDbContext>();

        services.AddSingleton<MainForm>();
        services.AddScoped<Form1>();
        services.AddScoped<Form2>();
        services.AddScoped<Form3>();

        services.AddTransient<IEmpRepository, EmpRepository>();
        services.AddTransient<ISisRepository, SisRepository>();
    }
}

到目前为止一切正常,我制作了 3 个表单来测试功能,在 Form1 中我注入了我需要的服务:

private readonly ISisRepository _sisRepository;
private readonly IEmpRepository _empRepository;
public Form1(ISisRepository sistRepository,
             IEmpRepository empRepository)
{
    _sisRepository= sistRepository;
    _empRepository = empRepository;

    InitializeComponent();
}

这个想法是使用,例如,_sisRepository 来更新记录,我第一次保存它就可以了,如果我再次点击保存,则会引发异常,在放置异常之前我已经告诉你我是使用通用存储库,这是下一个:

public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : Entity, new()
{
    protected readonly AnalistDbContext Db;
    protected readonly DbSet<TEntity> DbSet;
    protected Repository(AnalistDbContext db)
    {
        Db = db;
        DbSet = db.Set<TEntity>();

        Db.ChangeTracker.AutoDetectChangesEnabled = false;

        var existeBanco = (Db.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator).Exists();

        if (!existeBanco)
        {
            (Db.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator).Create();
            (Db.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator).CreateTables();
        }
    }
    public IEnumerable<TEntity> Buscar(Expression<Func<TEntity, bool>> predicate)
    {
        return DbSet.Where(predicate).AsNoTracking().ToList();
    }

    public virtual TEntity ObterPorId(Guid id)
    {
        return DbSet.AsNoTracking().FirstOrDefault(s => s.Id == id);
    }

    public virtual List<TEntity> ObterTodos()
    {
        return DbSet.AsNoTracking().ToList();
    }

    public void Adicionar(TEntity entity)
    {
        DbSet.Add(entity);
        SaveChanges();
    }

    public void Atualizar(TEntity entity)
    {
        DbSet.Update(entity);
        SaveChanges();
    }

    public void Remover(Guid id)
    {
        DbSet.Remove(new TEntity { Id = id });
        SaveChanges();
    }
    public int SaveChanges()
    {
        return Db.SaveChanges();
    }

    public void Dispose()
    {
        Db?.Dispose();
    }
}

例外是:

尽管消息很清晰,但我无法理解这是否是由于在表单的构造函数中使用依赖注入引起的问题,并且导致了与存储库实例相关的一些问题,看来我的对象仍然是与之前实例化的相同,因为正如我所说,此错误仅发生在第二次调用时。如果这真的是问题,你怎么能解决它?或者说到windows窗体,我会放弃使用依赖注入吗?

【问题讨论】:

  • 你能更简单地理解这个问题吗?有点难跟上
  • 考虑到一些答案,当我第二次更新记录时似乎是一个问题,因为它似乎已经被跟踪,显然我应该重新创建我的上下文,否则我得到的图像上述例外。但这就是问题所在,我想了解如何正确设置此场景。

标签: c# dependency-injection entity-framework-core inversion-of-control


【解决方案1】:

当您更新项目时,DbContext 开始跟踪该项目。当您进行第二次更新时,同一个 DbContext 会尝试跟踪具有 相同 idanother 项。这不是依赖注入的问题,而是注入的 AnalistDbContext 的生命周期及其跟踪的对象的问题。

通常,DbContext 将在每个操作的基础上进行实例化,而不是在整个表单的持续时间内存在。当两个用户尝试修改同一个实体时,这有助于防止不一致。你可以试试:

  • 更新 Form1 以使用可以创建存储库的工厂,并在使用后释放存储库
  • 更新 Repository 以使用可以创建 AnalistDbContext 的工厂,并在使用后释放上下文

如果您认为您将成为唯一更新条目的用户,并且不担心竞争条件或类似情况,您可以在尝试附加之前检查条目是否已被 db 上下文跟踪它。

【讨论】:

  • 对于调整选项,您能举个例子吗?我尝试了一些替代方案,但无济于事。
猜你喜欢
  • 2018-05-02
  • 2012-12-23
  • 2017-07-04
  • 2017-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
相关资源
最近更新 更多