Aktualizacja bazy danych SqlDataAdapter

0

Witajcie,

piszę właśnie moduł bazodanowy do mojej aplikacji i mam problem z aktualizacją danych. Korzystam z SqlClient'a. Pobieram dane za pomocą SqlDataAdapter'a poprzez odpowiednie ustawienie SqlConnection. Dane ładowane są do DataTable, a następnie do DataGridView.
Przy pomocy buttona aktualizuję dane w bazie danych za pomocą SqlDataAdapter/SqlCommandBuilder.

Program pobiera dane do DataTable bez problemu, wszystko ładuje się do DataGridView. Jednakże jakakolwiek próba aktualizacji danych w bazie danych kończy się fiaskiem. Dane nie są aktualizowane w bazie danych, lecz w DataTable (RowState zmienia się z Modified/Deleted/Added na Unchanged).

//EDIT
ConnectionState w momencie zapisu - Open.
Builder tworzy dobre zapytania. DataTable zwraca odpowiednie rekordy podczas wywołania GetChanges.

Po wyjściu z formatki z DataGridView i wejściu w nią ponownie program wyświetli zaktualizowane dane (uzupełni m.in. primary key). Natomiast jeśli wyłączę program i włączę ponownie, w DataGridzie ujrzę "pierwotny" stan bazy danych.

Poniżej zamieszczam napisane przeze mnie procedury do odczytu/zapisu danych z/do bazy danych:

 
    //Metoda odczytująca dane z bazy danych
    public class TADOReader
    {
        public DataTable Read(TADOConnection _connection)
        {
            DataTable dt = new DataTable();
            SqlDataAdapter adapter = new SqlDataAdapter(new SqlCommand("SELECT * FROM GroundWireDatabase", _connection.connection));
            adapter.Fill(dt);

            //Kolumna z kluczem głównym jako tylko do odczytu
            dt.Columns[0].ReadOnly = true;

            return dt;
        }
    }

    //Metoda zapisująca dane w bazie danych
    public class TADOWriter
    {
        public void Write(TADOConnection _connection, DataTable _table)
        {
            try
            {
                SqlDataAdapter adapter = new SqlDataAdapter(new SqlCommand("SELECT * FROM GroundWireDatabase",                  _connection.connection));
                SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
                adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
                adapter.DeleteCommand = builder.GetDeleteCommand(true);
                adapter.UpdateCommand = builder.GetUpdateCommand(true);
                adapter.InsertCommand = builder.GetInsertCommand(true);

                int result = adapter.Update(_table); // Zwraca liczbę <> 0
               // _table.AcceptChanges();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

    //Fragment klasy łączeniowej 
    public class TADOConnection
    {
        private const string DATASOURCE = @"(LocalDB)\v11.0";
        private const string INTEGRATED_SECURITY = "True";
        private const string ATTACH_DB_FILENAME = @"|DataDirectory|\IO\Database\GroundWireDatabase.mdf";
        private const string ConnectionString = "Data Source=" + DATASOURCE + 
                                                ";AttachDbFilename= " + ATTACH_DB_FILENAME +
                                                ";Integrated Security=" + INTEGRATED_SECURITY;

        public TADOConnection()
        {
            Fconnection = new SqlConnection(ConnectionString);
            Connect();
        }
    }

    //wywołania w formatce
        private void GroundWireDatabaseForm_Load(object sender, EventArgs e)
        {
            TADOReader reader = new TADOReader();
            dgGroundwire.DataSource = reader.Read(new TADOConnection());
        }

        private void btnAktualizuj_Click(object sender, EventArgs e)
        {
            TADOWriter writer = new TADOWriter();
            writer.Write(new TADOConnection(), dgGroundwire.DataSource as DataTable);
        }

Schema bazy danych

 
CREATE TABLE [dbo].[GroundWireDatabase] (
    [CableID]              INT        IDENTITY (1, 1) NOT NULL,
    [Producer]             TEXT       NULL,
    [CrossSection]         FLOAT (53) NULL,
    [Radius]               FLOAT (53) NULL,
    [Resistance]           FLOAT (53) NULL,
    [MagneticConductivity] FLOAT (53) NULL,
    PRIMARY KEY CLUSTERED ([CableID] ASC)
);

Z góry dziękuję za pomoc!
Pozdrawiam

0

wywołaj AcceptChanges() na adapterze

int result = adapter.Update(_table); //Zwraca 1
// _table.AcceptChanges();
adapter.AcceptChanges();
0

Klasa SqlDataAdapter nie ma zaimplementowanej metody AcceptChanges.

0

O ile dobrze pamiętam, to SqlDataAdapter wykonuje aktualizację na podstawie zmian, które zaszły w monitorowanych przez niego tabelach. Ty tworzysz nowy SqlDataAdapter w klasie zapisującej, który nie ma pojęcia o tym, co było odczytane, więc nie potrafi niczego zapisać. Spróbuj użyć jednego adaptera do odczytu i zapisu.

0

Niestety, nic to nie zmieniło. Z tego co wiem to SqlDataAdapter wykrywa zmiany na podstawie kontenera (tym przypadku DataTable) zawierającego zbiór wierszy typu DataRow. Rozróżnia ich stan na podstawie właściwości DataRowState. wywołując metodę Update na adapterze, adapter leci po wszystkich wierszach, aktualizuje dane i wywołuje na każdym wierszu AcceptChanges, co z kolei powoduje zmiane RowState wg dokumentacji MS.

0

Jak wygląda adapter.UpdateCommand .CommandText?
Coś w ogóle jest wysyłane do bazy czy nic?

0

UPDATE:
"UPDATE [GroundWireDatabase] SET [Producer] = @p1, [CrossSection] = @p2, [Radius] = @p3, [Resistance] = @p4, [MagneticConductivity] = @p5 WHERE (([CableID] = @p6) AND ((@p7 = 1 AND [CrossSection] IS NULL) OR ([CrossSection] = @p8)) AND ((@p9 = 1 AND [Radius] IS NULL) OR ([Radius] = @p10)) AND ((@p11 = 1 AND [Resistance] IS NULL) OR ([Resistance] = @p12)) AND ((@p13 = 1 AND [MagneticConductivity] IS NULL) OR ([MagneticConductivity] = @p14)))"

INSERT:
"INSERT INTO [GroundWireDatabase] ([Producer], [CrossSection], [Radius], [Resistance], [MagneticConductivity]) VALUES (@p1, @p2, @p3, @p4, @p5)"

DELETE:
"DELETE FROM [GroundWireDatabase] WHERE (([CableID] = @p1) AND ((@p2 = 1 AND [CrossSection] IS NULL) OR ([CrossSection] = @p3)) AND ((@p4 = 1 AND [Radius] IS NULL) OR ([Radius] = @p5)) AND ((@p6 = 1 AND [Resistance] IS NULL) OR ([Resistance] = @p7)) AND ((@p8 = 1 AND [MagneticConductivity] IS NULL) OR ([MagneticConductivity] = @p9)))"

O ile INSERT i DELETE wyglądają w miarę w porządku, to update nieco napuchnięty.

0

Przerobiłem klasę TADOWriter do tej postaci. Niestety, nadal nic. Ciekawe jest to, że ExecuteNonQuery zwraca wartość > 0.

 
    public class TADOWriter
    {
        private TADOConnection Connection;

        public void Write(TADOConnection _connection, DataTable _table)
        {
            foreach(DataRow row in _table.Rows)
            {
                switch(row.RowState)
                {
                    case DataRowState.Added:
                        Insert(row);
                        break;
                    case DataRowState.Deleted:
                        Delete(row);
                        break;
                    case DataRowState.Modified:
                        Update(row);
                        break;
                }
                row.AcceptChanges();
            }
        }

        private void Insert(DataRow _row)
        {
            SqlCommand cmd = new SqlCommand("INSERT INTO [GroundWireDatabase] ([Producer], [CrossSection], [Radius], [Resistance], [MagneticConductivity]) " +
                                            "VALUES (@p1, @p2, @p3, @p4, @p5)", Connection.connection);
            cmd.Parameters.AddWithValue("@p1", _row["Producer"]);
            cmd.Parameters.AddWithValue("@p2", _row["CrossSection"]);
            cmd.Parameters.AddWithValue("@p3", _row["Radius"]);
            cmd.Parameters.AddWithValue("@p4", _row["Resistance"]);
            cmd.Parameters.AddWithValue("@p5", _row["MagneticConductivity"]);

            cmd.ExecuteNonQuery();
        }

        private void Delete(DataRow _row)
        {
            SqlCommand cmd = new SqlCommand("DELETE FROM [GroundWireDatabase] WHERE [CableID] = @p1", Connection.connection);
            cmd.Parameters.AddWithValue("@p1", _row["CableID"]);

            cmd.ExecuteNonQuery();          
        }

        private void Update(DataRow _row)
        {
            SqlCommand cmd = new SqlCommand("UPDATE [GroundWireDatabase] SET [Producer] = @p1, [CrossSection] = @p2, " +
                                            "[Radius] = @p3, [Resistance] = @p4, [MagneticConductivity] = @p5 " +
                                            "WHERE [CableID] = @p6", Connection.connection);
            cmd.Parameters.AddWithValue("@p1", _row["Producer"]);
            cmd.Parameters.AddWithValue("@p2", _row["CrossSection"]);
            cmd.Parameters.AddWithValue("@p3", _row["Radius"]);
            cmd.Parameters.AddWithValue("@p4", _row["Resistance"]);
            cmd.Parameters.AddWithValue("@p5", _row["MagneticConductivity"]);
            cmd.Parameters.AddWithValue("@p6", _row["CableID"]);

            int result = cmd.ExecuteNonQuery();        
        }

        public TADOWriter()
        {
            Connection = new TADOConnection();
        }
    }
0

Jakieś pomysły?

0

Temat do zamknięcia, ADO -> ODBC rozwiązało problem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1