LINQ to DataSet, Операції DataTable
»» У ДАНІЙ СТАТТІ ВИКОРИСТОВУЄТЬСЯ ВИХІДНИЙ КІД ДЛЯ ПРИКЛАДІВ
На додаток до орієнтованих на DataRow операцій у класі DataRowExtensions передбачені деякі операції, специфічні для DataTable. Ці операції визначені у статичному класіSystem.Data.DataTableExtensions всередині збірки System.Data.Entity.dll.
AsEnumerable
Можливо, ви здивуєтеся, зустрівши тут операцію AsEnumerable. Ця операція спеціально призначена для класу DataTable та повертає послідовність об'єктів DataRow. Хоча вона не згадувалась досі, але ця операція викликалася майже в кожному прикладі.
Якщо ви подивитеся на статичний клас System.Data.DataTableExtensions, то побачите, що є операція AsEnumerable. Призначення цієї операції - повертати послідовність типу IEnumerable з об'єкта DataTable.
Операція AsEnumerable має один прототип, описаний нижче:
Ця операція, викликана на об'єкті DataTable, повертає послідовність об'єктів DataRow. Зазвичай так виглядає перший крок під час виконання запиту LINQ to DataSet на DataTable об'єкта DataSet. За рахунок виклику цієї операції можна отримати послідовність IEnumerable , де T є DataRow, що дозволяє викликати безліч операцій LINQ, які можуть бути викликані послідовності типу IEnumerable .
Оскільки виклик операції AsEnumerable — це перший крок під час запиту LINQ to DataSet, майже кожному прикладі з розділу LINQ to DataSet викликається операція AsEnumerable. Тому немає потреби наводити тут ще один приклад.
CopyToDataTable
Тепер, коли відомо, як запитувати та модифікувати значення DataColumn об'єкта DataRow, може виникнути питання, а як помістити цюпослідовність модифікованих об'єктів DataRow у DataTable?Операція CopyToDataTable призначена саме для цієї мети.
Операція CopyToDataTable має два прототипи, які описані нижче:
Перший прототип CopyToDataTable
Перший прототип викликається на IEnumerable і повертає DataTable. Він використовується для створення нового об'єкта DataTable із послідовності об'єктів DataRow. Перший прототип автоматично встановлює вихідні версії кожного поля, не вимагаючи явного виклику методу AcceptChanges.
Другий прототип викликається на IEnumerable вихідного DataTable, щоб оновити вже існуючий цільовий об'єкт DataTable, на основі вказаного значення LoadOptions.
Значення переданого аргументу LoadOptions інформує операцію у тому, що мають бути змінені лише вихідні значення стовпців, поточні значення чи й інші. Це корисно при керуванні змінами DataTable. Для LoadOption доступні такі значення:
OverwriteChanges : у кожному стовпці буде оновлено вихідне значення та поточне.
PreserveChanges : оновлюється лише вихідне значення кожного стовпця.
Upsert : оновлюється лише поточне значення кожного стовпця.
Однак, цей аргумент LoadOption створює невелику проблему. Зауважте, що опис кожного можливого значення посилається на оновлення значень стовпця. Це, звичайно ж, означає також оновлення стовпців запису, що вже знаходиться в цільовому DataTable. Як операція CopyToDataTable дізнається, який саме запис у цільовому DataTable відповідає запису у вихідному DataTable?
Іншими словами, коли операція CopyToDataTable намагається копіювати запис з вихідного DataTable до цільової та отримує параметр LoadOption, яким чином вонадізнається, чи слід просто додати запис з вихідного DataTable або ж оновити вже існуючий запис цільового DataTable? Відповідь — ніяк, якщо їй нічого не відомо про поля первинного ключа в DataTable.
Тому для правильної роботи цього прототипу операції CopyDataTable цільовий об'єкт DataTable повинен мати відповідну інформацію про поля первинного ключа. Якщо не вказати первинний ключ, цей прототип додасть всі записи вихідного об'єкта DataTable в цільовий об'єкт DataTable.
Тут є одна додаткова складність. Оскільки, використовуючи цей прототип, ви, можливо, зацікавлені у порівнянні вихідної та поточної версій значень полів, не забудьте, що з цим прототипом операції CopyDataTable поле не має вихідної версії, якщо не був викликанийметод AcceptChanges. Спроба звернутися до вихідної версії, коли вона не існує, призведе до створення винятку. Тим не менш, перед спробою отримати доступ до вихідної версії на кожному об'єкті DataRow можна викликатиметод HasVersion, щоб дізнатися, чи існує вона, і запобігти генерації виключення цього типу.
У прикладі застосування першого прототипу операції CopyToDataTable спочатку модифікується поле DataTable, за допомогою операції CopyToDataTable створюється новий об'єкт DataTable з модифікованого, після чого вміст нового об'єкта DataTable відображається на консоль:
Отже, спочатку створюється об'єкт DataTable із масиву студентів, як завжди робилося в попередніх прикладах. Потім вміст DataTable відображається на консолі. Після цього модифікується поле Name одного з об'єктів DataRow. Потім виклик CopyToDataTable створює новий об'єкт DataTable. І, нарешті, вміст новоствореного об'єкта DataTable відображається на консоль. Нижче показанорезультати:

Як бачите, у новому об'єкті DataTable є дані у модифікованій версії, чого й слід було очікувати.
У цьому прикладі демонструється застосування другого прототипу операції CopyToDataTable. Як згадувалося раніше, для правильної роботи аргументу LoadOption у цільовому об'єкті DataSet має визначити первинний ключ. У цьому прикладі вони не встановлюються, щоб можна було побачити поведінку без ключів. Оскільки цей приклад дещо складніший, наводяться додаткові пояснення:
Тут немає нічого особливого, за винятком посилання на вихідну версію поля Name у записі та відсутності генерації виключення при цьому, оскільки цей прототип операції CopyToDataTable встановлює вихідну версію полів автоматично.
У цьому сегменті коду вміст DataTable відображається на консоль. Так як первинний ключ для цільової таблиці не вказаний, при копіюванні дублікати записів не визначаються, тому всі скопійовані записи вихідного об'єкта DataTable будуть додані в цільовий об'єкт DataTable.
Також зверніть увагу, що звернення до вихідної версії даних поля відбувається, якщо метод HasVersion повертає true, вказуючи на наявність вихідної версії. Ось результат:

Як бачите, кілька записів тепер дубльовані, оскільки в цільовому DataTable не було вказано первинного ключа. Навіть щойно оновлений запис тепер зустрічається двічі у DataTable.
Може викликати здивування, навіщо поводитися з викликом методу HasVersion, якщо можна було просто викликати метод AcceptChanges? Якщо це зробити, всі поточні значення полів стануть вихідними версіями значень, і неможливо буде дізнатися, які записи були змінені. У прикладах, що розглядаються, потрібно, щоб при зміні запису значення вихідноїта поточної версій відрізнялися.
Вирішення проблеми попереднього прикладу полягає у вказівці первинного ключа цільового об'єкта DataTable. Нижче наведено приклад, аналогічний попередньому, але цього разу первинний ключ встановлено:
Єдина відмінність між цим прикладом і попереднім у тому, що додано рядок, що встановлює первинний ключ DataTable на ім'я newTable. І ось результат: