É este um bug no DataTable API? As alterações são armazenadas / executadas na “sequência errada”

StackOverflow https://stackoverflow.com/questions/1027095

  •  06-07-2019
  •  | 
  •  

Pergunta

Edit:. Quaisquer comentários se você acha que isso é um erro .NET ou não seria apreciada

Eu tenho um bug que eu consegui simplificar para o seguinte cenário:

Eu tenho um DataTable onde as chaves primárias devem ser mantidos consecutivo, por exemplo, se você inserir uma linha entre outras linhas, primeiro você deve incrementar o ID das linhas sucessivas para dar espaço, e, em seguida, inserir a linha.

E se você excluir uma linha, você deve diminuir o ID de quaisquer linhas sucessivas para preencher a lacuna deixada pela linha na tabela.

caso de teste que funciona corretamente

Comece com 3 linhas na tabela, com IDs 1, 2 e 3.

Depois de exclusão ID = 2, e conjunto ID = 2 onde ID = 3 (para preencher a lacuna); isso funciona corretamente. Os dataTable.GetChanges () contém a linha eliminada, e, em seguida, a linha modificada; quando você executar DataAdapter.Update (tabela) ele executa bem.

Caso de teste que não funciona

No entanto, se você começar com 2 linhas (IDs 1 e 2), então o conjunto de ID = 3, onde ID = 2, e inserir ID = 2, em seguida, confirmar (ou aceitar) muda. Este deve ser agora ser o mesmo estado como o primeiro teste.

Então você faz os mesmos passos como antes, ou seja, de exclusão ID = 2 e set ID = 2, onde ID = 3, mas agora os dataTable.GetChanges () estão na ordem errada. A primeira linha é uma linha modificada, e a segunda linha representa a linha excluída. Então, se você tentar DataAdapter.Update (tabela) ele vai dar uma violação de chave primária -. Ele tentou modificar uma linha a uma linha já existente, antes de excluir

Solução

Não consigo pensar em uma solução para o problema, ou seja, forçá-lo para que linhas excluídas são cometidos primeiro, e depois modificado linhas, e depois acrescentou linhas. Mas por que isso está acontecendo? Existe uma outra solução?

Eu acho que eu tenho visto um "problema" similar antes com dicionários, que se você adicionar alguns itens, excluir, em seguida, re-inseri-los, então eles não vão estar na mesma seqüência que você adicionou-los (quando você enumerar a dicionário).

Aqui estão dois testes NUnit que mostram o problema:

[Test]
public void GetChanges_Working()
{
    // Setup ID table with three rows, ID=1, ID=2, ID=3
    DataTable idTable = new DataTable();
    idTable.Columns.Add("ID", typeof(int));

    idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };

    idTable.Rows.Add(1);
    idTable.Rows.Add(2);
    idTable.Rows.Add(3);

    idTable.AcceptChanges();

    // Delete ID=2, and move old ID=3 to ID=2
    idTable.Select("ID = 2")[0].Delete();
    idTable.Select("ID = 3")[0]["ID"] = 2;

    // Debug GetChanges
    foreach (DataRow row in idTable.GetChanges().Rows)
    {
        if (row.RowState == DataRowState.Deleted)
            Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
        else
            Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
    }

    // Check GetChanges
    Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
    Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}

Output:

Deleted: 2
Modified: 3 = 2

1 passed, 0 failed, 0 skipped, took 4.27 seconds (NUnit 2.4).

Em seguida teste:

[Test]
public void GetChanges_NotWorking()
{
    // Setup ID table with two rows, ID=1, ID=2
    DataTable idTable = new DataTable();
    idTable.Columns.Add("ID", typeof(int));

    idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };

    idTable.Rows.Add(1);
    idTable.Rows.Add(2);

    idTable.AcceptChanges();

    // Move old ID=2 to ID=3, and add ID=2
    idTable.Select("ID = 2")[0]["ID"] = 3;
    idTable.Rows.Add(2);

    idTable.AcceptChanges();

    // Delete ID=2, and move old ID=3 to ID=2
    idTable.Select("ID = 2")[0].Delete();
    idTable.Select("ID = 3")[0]["ID"] = 2;

    // Debug GetChanges
    foreach (DataRow row in idTable.GetChanges().Rows)
    {
        if (row.RowState == DataRowState.Deleted)
            Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
        else
            Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
    }

    // Check GetChanges
    Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
    Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}

Output:

Modified: 3 = 2
Deleted: 2
TestCase 'GetChanges_NotWorking'
failed: 
  1st row in GetChanges should be deleted row
  Expected: Deleted
  But was:  Modified
Foi útil?

Solução

Não é um bug, o ponto é que você está usando ID do em um (muito) meio fora do padrão. Duas respostas:

1) Use DataTable.GetChanges (DataRowState.Modified) para processar suas atualizações, a fim (eu acho que seria eliminado, modificado, inserido). Isto é o que você tem a ver com o mestre relações / detalhe bem (antes .net 3.0)

2) Repensar o seu design, em de ID geral deve ser imutável e permitir lacunas etc. Isso fará com que todas as suas operações de banco de dados muito mais confiável e mais fácil. Você pode usar outra coluna para manter a numeração sequencial de presente para o usuário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top