วิธีง่ายๆในการคัดลอกหรือโคลน DataRow?


118

ฉันกำลังมองหาวิธีง่ายๆในการสร้างโคลน DataRow เช่นการถ่ายภาพรวมของ Row นั้นและบันทึกไว้ จากนั้นค่าของ Row ดั้งเดิมจะเปลี่ยนได้ฟรี แต่เรายังมีสำเนาที่บันทึกไว้อีกอันซึ่งไม่เปลี่ยนแปลง วิธีนี้เป็นวิธีที่ถูกต้องหรือไม่?

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

สิ่งนี้จะตั้งค่าการอ้างอิง ItemArray ของ Snapshot ให้ชี้ไปที่รายการใน Source หรือทำสำเนาแยกต่างหากหรือไม่? ฉันควรทำสิ่งนี้แทนหรือไม่

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

แก้ไข: ฉันไม่คิดว่าข้อมูลโค้ดที่สองรวบรวมได้จริง


ฉันไม่แน่ใจว่าฉันเข้าใจคุณต้องการคัดลอก datarow จากตารางหนึ่งไปยังอีกตารางหรือไม่ ถ้าเป็นเช่นนั้นฉันเชื่อว่าการใช้ DataTable.ImportRow คือสิ่งที่คุณต้องการ
Mo Patel

โอเคฉันเห็นว่าคำถามของฉันต้องทำงานใหม่แล้ว
Paul Matthews

2
โปรดทราบว่าในบางสถานการณ์คุณอาจไม่จำเป็นต้องทำเช่นนี้เนื่องจากตัว datarow รองรับการแก้ไขธุรกรรมด้วย BeginEdit / EndEdit / CancelEdit นอกจากนี้คุณยังสามารถโทร. ปฏิเสธการเปลี่ยนแปลงได้
peterG

คำตอบ:


185

คุณสามารถใช้ImportRowวิธีการคัดลอก Row จาก DataTable ไปยัง DataTable ด้วยสคีมาเดียวกัน:

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

ปรับปรุง:

ด้วยการแก้ไขใหม่ของคุณฉันเชื่อว่า:

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

จะทำงาน


Apparently Clone () ให้สำเนาตื้น ๆ เท่านั้น คุณคิดว่าจะเพียงพอที่จะสร้างสำเนาที่เหมือนกันหรือต้องใช้การโคลนแบบลึกหรือไม่?
Paul Matthews

5
@PaulMatthews: โชคดีที่ DataTable มีชนิดของค่าไม่ใช่ประเภทอ้างอิงดังนั้นสำเนาตื้นในระบบปฏิบัติการประเภทเดียวกันกับสำเนาแบบลึก
cuongle

16
สำหรับคนที่พบโพสต์นี้ฉันจะเพิ่มสิ่งต่อไปนี้ตามที่ฉันถูกถามบ่อยๆดังนั้นฉันเดาว่าคนอื่นอาจสับสน คัดลอกโครงสร้างเท่านั้นคัดลอกคัดลอกโครงสร้างจากนั้นข้อมูล มีการกล่าวว่าอีกวิธีง่ายๆในการคัดลอกข้อมูลเมื่อทั้งสองสร้างอินสแตนซ์ตารางแล้วคือการสร้างแถวใหม่ในตารางปลายทางและใช้สิ่งต่อไปนี้: destRow.ItemArray = sourceRow.ItemArrayจากนั้นเพิ่มแถวกลับด้วยdestTable.Rows.Add(destRow);
Franck

1
ฉันกำลังพยายามใช้วิธีนี้ในการรับโคลนของ datarow ฉันทำตามขั้นตอนแล้วฉันล้างข้อมูลที่มีแถวแหล่งที่มาและตอนนี้ฉันมีแถวต้นทางพร้อมช่องว่าง
Sergеу Isupov

ฉันพบว่าการใช้เมธอด ImportRow ได้ผลสำหรับฉันโดยที่วิธี NewRow ใช้ไม่ได้
OldDog

2

หมายเหตุ: คำตอบ helfpul ของ cuongleมีส่วนผสมทั้งหมด แต่วิธีแก้ปัญหาสามารถปรับปรุงได้ (ไม่จำเป็นต้องใช้.ItemArray) และสามารถปรับแต่งใหม่เพื่อให้ตรงกับคำถามที่ถามได้ดีขึ้น

ในการสร้างโคลน (แยก) ของSystem.Data.DataRowอินสแตนซ์ที่กำหนดคุณสามารถทำสิ่งต่อไปนี้:

// 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];

หมายเหตุ: การโคลนนิ่งแบบตื้นจะดำเนินการซึ่งทำงานตามที่เป็นอยู่กับค่าคอลัมน์ที่เป็นอินสแตนซ์ประเภทค่าแต่จำเป็นต้องมีงานมากขึ้นเพื่อสร้างสำเนาค่าคอลัมน์อิสระที่มีอินสแตนซ์ประเภทการอ้างอิง (และการสร้างสำเนาอิสระดังกล่าวไม่สามารถทำได้เสมอไป )


1

ดูเหมือนว่าคุณไม่ต้องการเก็บ DataTable ทั้งหมดไว้เป็นสำเนาเพราะคุณต้องการเพียงบางแถวใช่ไหม หากคุณมี creteria คุณสามารถระบุด้วยการเลือกบนตารางคุณสามารถคัดลอกเฉพาะแถวเหล่านั้นไปยังอาร์เรย์สำรองข้อมูลเพิ่มเติมของ DataRow เช่น

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

ฟังก์ชัน. select () มีหลายตัวเลือกและฟังก์ชันนี้สามารถอ่านเป็น SQL ได้

SELECT * FROM sourceTable WHERE searchColumn = value;

จากนั้นคุณสามารถนำเข้าแถวที่คุณต้องการตามที่อธิบายไว้ข้างต้น

targetTable.ImportRows(rows[n])

... สำหรับ n ที่ถูกต้องที่คุณต้องการ แต่คอลัมน์จะต้องเหมือนกันในแต่ละตาราง

บางสิ่งที่คุณควรทราบเกี่ยวกับ ImportRow ก็คือจะมีข้อผิดพลาดระหว่างรันไทม์เมื่อใช้คีย์หลัก!

ก่อนอื่นฉันต้องการตรวจสอบว่ามีแถวอยู่แล้วหรือไม่ซึ่งล้มเหลวเนื่องจากคีย์หลักหายไป แต่การตรวจสอบก็ล้มเหลวเสมอ ในที่สุดฉันก็ตัดสินใจล้างแถวที่มีอยู่ทั้งหมดและนำเข้าแถวที่ฉันต้องการอีกครั้ง

ประเด็นที่สองช่วยให้เข้าใจสิ่งที่เกิดขึ้น วิธีที่ฉันใช้ฟังก์ชันนำเข้าคือการทำซ้ำแถวด้วยรายการที่แลกเปลี่ยนในคอลัมน์เดียว ฉันตระหนักว่ามันเปลี่ยนแปลงอยู่เสมอและยังคงเป็นการอ้างอิงถึงแถวในอาร์เรย์ ก่อนอื่นฉันต้องนำเข้าต้นฉบับจากนั้นจึงเปลี่ยนรายการที่ฉันต้องการ

การอ้างอิงยังอธิบายข้อผิดพลาดของคีย์หลักที่ปรากฏขึ้นเมื่อฉันพยายามนำเข้าแถวเป็นครั้งแรกเนื่องจากมีการเพิ่มขึ้นเป็นสองเท่า


-4

แต่เพื่อให้แน่ใจว่าแถวใหม่ของคุณสามารถเข้าถึงได้ในตารางใหม่คุณต้องปิดตาราง:

DataTable destination = new DataTable(source.TableName);
destination = source.Clone();
DataRow sourceRow = source.Rows[0];
destination.ImportRow(sourceRow);

3
จุดของโค้ดบรรทัดแรกคืออะไรหากโค้ดบรรทัดที่สองกำหนดตัวแปรใหม่
Erik Philips

คำตอบนี้สามารถใช้คำอธิบายเพิ่มเติมได้ (และฉันไม่รู้ว่าจำเป็นต้องปิดตารางหมายถึงอะไร) และ @ErikPhilips มีประเด็น ( DataTable destination = source.Clone()ควรทำ) แต่อย่างอื่นคำตอบนี้ดีอย่างสมบูรณ์แบบและยังดีกว่าสำหรับ.ItemArrayแนวทางในคำตอบที่ยอมรับ
mklement0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.