Prosty sposób na skopiowanie lub sklonowanie DataRow?

118

Szukam prostego sposobu na utworzenie klonu DataRow. Coś jak zrobienie migawki tego rzędu i zapisanie go. Wartości oryginalnego wiersza można następnie zmienić, ale nadal mamy inną zapisaną kopię, która się nie zmienia. Czy to jest właściwy sposób?

DataRow Source, Destination;
// Assume we create some columns and fill them with values
Destination.ItemArray = Source.ItemArray;

Czy spowoduje to ustawienie odniesienia ItemArray w Snapshot tak, aby wskazywało na ten w źródle, czy faktycznie tworzy oddzielną kopię? Powinienem to zrobić zamiast tego?

Destination.ItemArray = Source.ItemArray.Clone();

EDYCJA: Nie sądzę, aby drugi fragment kodu faktycznie się kompilował.

Paul Matthews
źródło
Nie jestem pewien, czy rozumiem, chcesz skopiować wiersz danych z jednej tabeli do drugiej? Jeśli tak, to uważam, że szukasz DataTable.ImportRow.
Mo Patel,
Ok, widzę, że moje pytanie wymaga teraz ponownej odpowiedzi
Paul Matthews
2
Zauważ, że w niektórych scenariuszach może nie być konieczne robienie tego, ponieważ sam datarow obsługuje edycję transakcyjną za pomocą BeginEdit / EndEdit / CancelEdit; możesz również wywołać na nim .RejectChanges.
peterG

Odpowiedzi:

185

Możesz użyć ImportRowmetody, aby skopiować wiersz z DataTable do DataTable z tym samym schematem:

var row = SourceTable.Rows[RowNum];
DestinationTable.ImportRow(row);

Aktualizacja:

Wierzę, że dzięki Twojej nowej edycji:

var desRow = dataTable.NewRow();
var sourceRow = dataTable.Rows[rowNum];
desRow.ItemArray = sourceRow.ItemArray.Clone() as object[];

będzie działać

cuongle
źródło
Najwyraźniej Clone () zapewnia tylko skróconą kopię. Myślisz, że to wystarczy do stworzenia identycznej kopii, czy też potrzebny jest głęboki klon?
Paul Matthews
5
@PaulMatthews: Szczęśliwie DataTable zawiera typy wartości, a nie ref typ, więc płytkie kopię w rodzaju wartości os samo z głębokim kopii
cuongle
16
Dla osób, które znajdą ten post, dodam następujące, ponieważ często mnie pytano, więc myślę, że inni ludzie mogą być zdezorientowani. Klonuj kopiuj tylko strukturę, Kopiuj kopiuj strukturę, a następnie dane. Mówi się, że innym prostym sposobem kopiowania danych po utworzeniu instancji obu tabel jest utworzenie nowego wiersza w tabeli docelowej i użycie następującego: destRow.ItemArray = sourceRow.ItemArraynastępnie proste dodanie wiersza z powrotem za pomocądestTable.Rows.Add(destRow);
Franck
1
Próbuję użyć tej metody, aby uzyskać klon datarow. Wykonuję następujące kroki, następnie usuwam datatable, który zawiera wiersz źródłowy, a teraz mam wiersz źródłowy z pustymi polami.
Sergеу Isupov
Okazało się, że metoda ImportRow zadziałała u mnie, podczas gdy metoda NewRow nie.
OldDog
2

Uwaga: pomocna odpowiedź Cuongle zawiera wszystkie składniki, ale rozwiązanie można usprawnić (nie ma potrzeby .ItemArray) i można je przeformułować, aby lepiej dopasować zadane pytanie.

Aby utworzyć (izolowany) klon danej System.Data.DataRowinstancji , możesz wykonać następujące czynności:

// Assume that variable `table` contains the source data table.

// Create an auxiliary, empty, column-structure-only clone of the source data table.
var tableAux = table.Clone();
// Note: .Copy(), by contrast, would clone the data rows also.

// Select the data row to clone, e.g. the 2nd one:
var row = table.Rows[1];

// Import the data row of interest into the aux. table.
// This creates a *shallow clone* of it.
// Note: If you'll be *reusing* the aux. table for single-row cloning later, call
//       tableAux.Clear() first.
tableAux.ImportRow(row);

// Extract the cloned row from the aux. table:
var rowClone = tableAux.Rows[0];

Uwaga: Wykonywane jest płytkie klonowanie , które działa tak jak jest z wartościami kolumn, które są instancjami typu wartości , ale potrzeba więcej pracy, aby również utworzyć niezależne kopie wartości kolumn zawierających instancje typu referencyjnego (a tworzenie takich niezależnych kopii nie zawsze jest możliwe ).

mklement0
źródło
1

Wygląda na to, że nie chcesz zachować całego DataTable jako kopii, ponieważ potrzebujesz tylko kilku wierszy, prawda? Jeśli masz kreterię, którą możesz określić za pomocą zaznaczenia w tabeli, możesz skopiować tylko te wiersze do dodatkowej kopii zapasowej tablicy DataRow, takiej jak

DataRow[] rows = sourceTable.Select("searchColumn = value");

Funkcja .Select () ma kilka opcji, a tę można np. Odczytać jako SQL

SELECT * FROM sourceTable WHERE searchColumn = value;

Następnie możesz zaimportować żądane wiersze, jak opisano powyżej.

targetTable.ImportRows(rows[n])

... dla dowolnego poprawnego n, które chcesz, ale kolumny muszą być takie same w każdej tabeli.

Kilka rzeczy, które powinieneś wiedzieć o ImportRow, to fakt, że podczas używania kluczy podstawowych będą występować błędy!

Najpierw chciałem sprawdzić, czy istnieje już wiersz, który również nie powiódł się z powodu braku klucza podstawowego, ale potem sprawdzenie zawsze kończyło się niepowodzeniem. W końcu zdecydowałem się całkowicie wyczyścić istniejące wiersze i ponownie zaimportować te, które chciałem.

Druga kwestia pomogła zrozumieć, co się dzieje. Sposób, w jaki używam funkcji importu, polega na duplikowaniu wierszy z wymienionym wpisem w jednej kolumnie. Zdałem sobie sprawę, że zawsze się to zmieniało i nadal było to odniesienie do wiersza w tablicy. Najpierw musiałem zaimportować oryginał, a następnie zmienić wpis, który chciałem.

W odwołaniu wyjaśniono również błędy klucza podstawowego, które pojawiły się, gdy po raz pierwszy próbowałem zaimportować wiersz, ponieważ naprawdę został podwojony.

Bolle
źródło
-4

Aby jednak upewnić się, że nowy wiersz jest dostępny w nowej tabeli, musisz zamknąć tabelę:

DataTable destination = new DataTable(source.TableName);
destination = source.Clone();
DataRow sourceRow = source.Rows[0];
destination.ImportRow(sourceRow);
rdjabarov
źródło
3
Jaki jest sens pierwszej linii kodu, jeśli druga linia kodu ponownie przypisuje zmienną?
Erik Philips,
Ta odpowiedź przydałaby się więcej wyjaśnień (i nie wiem, co oznacza konieczność zamknięcia tabeli ), a @ErikPhilips ma rację ( DataTable destination = source.Clone()powinien zrobić), ale poza tym ta odpowiedź jest całkowicie w porządku, a nawet lepsza niż .ItemArraypodejście w zaakceptowanej odpowiedzi.
mklement0