简体   繁体   English

使用实体框架和 PostgreSQL 的 SaveChanges 错误

[英]Errors in SaveChanges using entity framework and PostgreSQL

With the codes below, I'm trying to insert a new object into my PostgreSQL database, using the entity framework:使用下面的代码,我正在尝试使用实体框架将新的 object 插入到我的 PostgreSQL 数据库中:

Class campo Class 坎波

public class campo
{
    public int id { get; set; }
    public int id_extrator { get; set; }
    public string nome { get; set; }
    public bool campo_selecionado { get; set; }

}

Calling the Event:调用事件:

private void btnSalvarDetalhesExtrator_Click(object sender, EventArgs e)
{
    try
    {
        _campoDal = new CampoDal();
        List<campo> listaCampos = new List<campo>();
        campo dadosCampo;
        for (int a = 0; a < gvCamposExtrator.RowCount; a++)
        {
            dadosCampo = new campo();
            dadosCampo.id_extrator = _idExtrator;
            dadosCampo.nome = (string)gvCamposExtrator.Rows[a].Cells["Nome"].Value;
            dadosCampo.campo_selecionado = (bool)gvCamposExtrator.Rows[a].Cells["Campo_Selecionado"].Value;
            _campoDal.AdicionarCampo(dadosCampo);
        }
    }
}

Adding to the database添加到数据库

public campo AdicionarCampo(campo dadosCampo)
{
    try
    {
        _dbContext.Campos.Add(new campo
            {
                nome = dadosCampo.nome,
                id_extrator = dadosCampo.id_extrator,
                campo_selecionado = dadosCampo.campo_selecionado
            }
        );
        _dbContext.SaveChanges();
        return dadosCampo;
    }
    catch (Exception ex)
    {
        throw;
    }
}

However, the error below is shown when I try to perform this action, which is similar to the ZombieCheck of SQLTransaction.但是,当我尝试执行此操作时,会显示以下错误,这类似于 SQLTransaction 的 ZombieCheck。

Error ZombieCheck Npgsql错误 ZombieCheck Npgsql

Stack Tracer:堆栈跟踪器:

   em Npgsql.NpgsqlTransaction.CheckReady()
   em Npgsql.NpgsqlTransaction.get_DbConnection()
   em System.Data.Common.DbTransaction.get_Connection()
   em System.Data.Entity.Infrastructure.Interception.DbTransactionDispatcher.Dispose(DbTransaction transaction, DbInterceptionContext interceptionContext)
   em System.Data.Entity.Core.EntityClient.EntityTransaction.Dispose(Boolean disposing)
   em System.Data.Common.DbTransaction.Dispose()
   em System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   em System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
   em System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass148_0.<SaveChangesInternal>b__0()
   em System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func`1 operation)
   em System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
   em System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
   em System.Data.Entity.Internal.InternalContext.SaveChanges()
   em System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   em System.Data.Entity.DbContext.SaveChanges()
   em ConectorAditi.DAL.Concrete.CampoDal.AdicionarCampo(campo dadosCampo) na C:\Users\Joao Pedro\source\repos\ConectorAditi\ConectorAditi\DAL\Concrete\CampoDal.cs:linha 29

Trying to solve or give a temporary solution to this, instead of returning a throw in the catch block I initially did not write anything in the block or put it to return the object I was trying to add, as if it had worked.试图解决这个问题或给出一个临时解决方案,而不是在 catch 块中返回一个 throw,我最初没有在块中写任何东西,或者把它返回我试图添加的 object,就好像它已经工作一样。

public campo AdicionarCampo(campo dadosCampo)
{
    try
    {
        _dbContext.Campos.Add(new campo
            {
                nome = dadosCampo.nome,
                id_extrator = dadosCampo.id_extrator,
                campo_selecionado = dadosCampo.campo_selecionado
            }
        );
        return dadosCampo;
    }
    catch (Exception ex)
    {
        return dadosCampo;
    }
}

In this implementation the data is saved in the database, however in each loop interaction the SaveChanges saves the new object and those that have already been inserted, instead of inserting only the data of the new instantiated object.在这个实现中,数据保存在数据库中,但是在每个循环交互中,SaveChanges 保存新的 object 和那些已经插入的数据,而不是只插入新实例化的 object 的数据。

I don't know if the problem may be there, but the code below refers to the context class of the database不知道是不是问题,但是下面的代码是指数据库的上下文class

public class ApplicationDataBase : DbContext
{
    private readonly string schema;
    public DbSet<assunto> Assuntos { get; set; }
    public DbSet<atualizacao_campos_realizada> AtualizacoesCamposRealizadas { get; set; }
    public DbSet<campo> Campos { get; set; }
    public DbSet<carga_realizada> CargaRealizadas { get; set; }
    public DbSet<data_base> DataBases { get; set; }
    public DbSet<extrator> Extratores { get; set; }
    public DbSet<tipo_carga> TiposCargas { get; set; }

    public ApplicationDataBase(string schema) : base("dbConectionString")
    {
        this.schema = schema;
    }
    protected override void OnModelCreating(DbModelBuilder builder)
    {
        builder.Conventions.Remove<PluralizingTableNameConvention>();
        Database.SetInitializer<ApplicationDataBase>(null);
        builder.HasDefaultSchema(this.schema);
        base.OnModelCreating(builder);
    }
}

Would anyone know where I can be wrong in this implementation and how can I solve the "ZombieCheck" problems of NpgsqlTransaction or even that of data duplication when using SaveChanges?有谁知道我在这个实现中可能出错的地方,以及在使用 SaveChanges 时如何解决 NpgsqlTransaction 的“ZombieCheck”问题甚至数据重复问题? I've tried some solutions and implementations but none has solved these cases.我尝试了一些解决方案和实现,但没有一个解决了这些情况。

EDIT:编辑:

As a temporary solution, I added the line below in the catch block that removes the entity that was added from context tracking, finding this solution through the comment made by @Sowmyadhar Gourishetty:作为临时解决方案,我在 catch 块中添加了以下行,该行从上下文跟踪中删除了添加的实体,通过@Sowmyadhar Gourishetty 的评论找到了这个解决方案:

        catch (Exception ex)
        {
            _dbContext.Entry(dadosCampo).State = EntityState.Detached;

            return dadosCampo;
         }

However, I still haven't found a way to avoid the "ZombieCheck" error posted in the first image, thus preventing it from entering the catch block.但是,我仍然没有找到避免第一张图片中发布的“ZombieCheck”错误的方法,从而阻止它进入 catch 块。 If anyone can help, I appreciate it.如果有人可以提供帮助,我将不胜感激。

I think your issue may be that EF does not know what your primary key is.我认为您的问题可能是 EF 不知道您的主键是什么。

Try adding the following attribute to property id in class campo :尝试将以下属性添加到 class campo中的属性id

[Key]
public int id { get; set; }

This attribute can be found in namespace System.ComponentModel.DataAnnotations .此属性可以在命名空间System.ComponentModel.DataAnnotations中找到。

Also, you don't need to create a new entity.此外,您不需要创建新实体。 You can just add the one you are passing on to the method.您只需将要传递的那个添加到方法中即可。 There is no need to return anything now.现在没有必要退回任何东西。 Also, there is no point on catching the exception if you are just going to rethrow it.此外,如果您只是要重新抛出异常,那么捕获异常是没有意义的。 The only time this is useful is if you need to add additional information about what is happening inside the method.唯一有用的是如果您需要添加有关方法内部发生的事情的其他信息。

Your method is then reduced to this:然后您的方法简化为:

public void AdicionarCampo(campo dadosCampo)
{
    _dbContext.Campos.Add(dadosCampo);
    _dbContext.SaveChanges();
}

All this being said, your code will currently always add new records.话虽如此,您的代码目前总是会添加新记录。 If what you wish to do is update existing ones and only add new ones, then you will need to retrieve the objects from the context first (when they exist), update them and then call the SaveChanges method in the context.如果您希望更新现有对象并仅添加新对象,那么您需要先从上下文中检索对象(当它们存在时),更新它们,然后在上下文中调用SaveChanges方法。

One thing I will caution against is the fact that you are keeping an internal context instance ( _dbContext ).我要注意的一件事是您保留了一个内部上下文实例 ( _dbContext )。 This means that you need to make sure the context is in the right state when you use it.这意味着您在使用时需要确保上下文在正确的 state 中。 The context is meant to be used as a unit of work, so you should only keep it alive in this manner if you are going to be allowing a series of operations that will ultimately be "committed" together.上下文旨在用作一个工作单元,因此如果您要允许最终将“提交”在一起的一系列操作,则应该仅以这种方式保持它的活动状态。 In fact, if this doesn't fix your issue, chances are you are doing something else with the DAL (and hence, the context) prior to these calls that may cause the issue.事实上,如果这不能解决您的问题,那么您很可能在这些可能导致问题的调用之前对 DAL(以及上下文)进行了其他操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM