Метод Refresh()
31LINQ --- LINQ to DataSet и SQL --- Метод Refresh()
»» В ДАННОЙ СТАТЬЕ ИСПОЛЬЗУЕТСЯ ИСХОДНЫЙ КОД ДЛЯ ПРИМЕРОВ
Метод Refresh позволяет вручную обновлять сущностные объекты из базы данных. В некоторых ситуациях это делается при вызове метода ResolveAll коллекции ChangeConflicts объекта DataContext в случае возникновения конфликтов во время вызова метода SubmitChanges. Однако могут быть ситуации, в которых метод SubmitChanges никогда не вызывается, но нужно получать обновления из базы данных.
Примером может служить приложение, которое отображает данные о состоянии некоторого сущностного объекта, системы или процесса, доступные только для чтения. Могут понадобиться регулярные обновления данных из базы через какие-то интервалы времени. Для этой цели пригодится метод Refresh. С помощью метода Refresh можно обновлять отдельный сущностный объект либо последовательность сущностных объектов — имеется в виду результат запроса LINQ to SQL.
Метод Refresh имеет три прототипа, которые описаны ниже:
- Первый прототип Refresh
-
void Refresh(RefreshMode mode, object entity)
Этот метод принимает режим обновления и единственный сущностный объект и ничего не возвращает.
- Второй прототип Refresh
-
void Refresh(RefreshMode mode, params object[] entities)
Этот метод принимает режим обновления и массив params сущностных объектов и ничего не возвращает.
- Третий прототип Refresh
-
void Refresh(RefreshMode mode, System.Collections.IEnumerable entities)
Этот метод принимает режим обновления и последовательность сущностных объектов и ничего не возвращает.
Перечисление RefreshMode имеет три возможных значения: KeepChanges, KeepCurrentValues и OverwriteCurrentValues.
В документации Visual Studio о перечислении RefreshMode эти значения определены так, как описано ниже:
- KeepCurrentValues
Заставляет метод Refresh обменять исходное значение объекта со значениями, извлеченными из базы данных
- KeepChanges
Заставляет метод Refresh сохранять текущее значение, которое было изменено, но обновляет другие значения прочитанными из базы
- OverwriteCurrentValues
Заставляет метод Refresh заменить все текущие значения значениями, взятыми из базы
Для примера первого прототипа в следующем примере запрашивается заказчик с использованием LINQ to SQL и на консоль выводится имя и должность контактного лица. Затем с помощью ADO.NET имя контактного лица этого заказчика изменяется в базе данных. Должность контактного лица модифицируется в сущностном объекте. И чтобы доказать, что текущий сущностный объект не имеет понятия об изменении в базе данных, но имеет измененную должность контакта, снова отображается имя и должность контактного лица, и вы увидите, что имя контактного лица не изменилось, тогда как должность изменилась.
После этого вызывается метод Refresh с RefreshMode, равным KeepChanges, и контактное имя и должность из сущностного объекта выводится на консоль еще раз. Можно убедиться, что сущностный объект действительно содержит новое значение имени контактного лица из базы данных, в то же время сохраняя изменение, внесенное в должность контакта:
// Используйте свое подключение
Northwind db = new Northwind(@"Data Source=MICROSOF-1EA29E\SQLEXPRESS;
Initial Catalog=C:\NORTHWIND.MDF;
Integrated Security=True");
Customer cust = (from c in db.Customers
where c.CustomerID == "GREAL"
select c).Single<Customer>();
Console.WriteLine("Исходное имя заказчика {0}, ContactTitle - {1}.{2}",
cust.ContactName, cust.ContactTitle, System.Environment.NewLine);
ExecuteStatementInDb(String.Format(
@"update Customers set ContactName = 'Brad Radaker' where CustomerID = 'GREAL'"));
cust.ContactTitle = "Chief Technology Officer";
Console.WriteLine("Имя заказчика перед обновлением {0}, ContactTitle - {1}.{2}",
cust.ContactName, cust.ContactTitle, System.Environment.NewLine);
db.Refresh(RefreshMode.KeepChanges, cust);
Console.WriteLine("Имя заказчика после обновления {0}, ContactTitle - {1}.{2}",
cust.ContactName, cust.ContactTitle, System.Environment.NewLine);
ExecuteStatementInDb(String.Format(
@"update Customers set ContactName = 'Howard Snyder' where CustomerID = 'GREAL'"));
В предыдущем коде выполняется запрос LINQ to SQL для получения ссылки на объект Customer. Затем на консоль выводятся значения ContactName и ContactTitle объекта Customer.
После этого с помощью ADO.NET значение ContactName заказчика обновляется в базе данных и модифицируется ContactTitle в извлеченном сущностном объекте Customer. В этой точке сущностный объект Customer не знает, что ContactName было изменено в базе данных, и это доказывается выводом на консоль значений полей ContactName и ContactTitle объекта Customer.
Далее вызывается метод RefreshMethod с KeepChanges из RefreshMode. Это должно заставить загрузиться в сущностный объект любые свойства объекта Customer, которые были изменены в базе данных. В рассматриваемом случае, поскольку значение ContactName было изменено в базе данных, оно должно быть обновлено из этой базы данных.
Затем на консоль выводятся значения ContactName и ContactTitle объекта Customer, при этом для ContactName должно быть отображено значение, взятое из базы данных, а для ContactTitle — значение, измененное в сущностном объекте.
И, наконец, исходные значения в базе данных восстанавливаются, чтобы этот пример можно было запустить снова, и чтобы последующие примеры сохранили работоспособность.
Ниже показаны результаты работы кода:
Как видите, сущностный объект не знает об изменении ContactName на "Brad Radaker" в базе данных, пока не будет вызван метод Refresh.
Для примера вызова второго прототипа в показанном ниже примере производится извлечение заказчиков из региона "WA" с использованием LINQ to SQL.
После этого осуществляется перечисление членов возвращенной последовательности объектов Customer с выводом на консоль их свойств CustomerID, Region и Country. Затем с помощью ADO.NET обновляется поле Country у каждого заказчика в базе данных, чьим регионом является "WA". В этой точке значение поля Country для этих заказчиков в базе данных будет отличаться от значения, которое есть в соответствующем свойстве извлеченных ранее сущностных объектов. Снова выполняется перечисление последовательности извлеченных заказчиков — просто чтобы доказать, что сущностные объекты не имеют понятия об изменении поля Region в базе данных.
Далее на последовательности объектов Customer вызывается операция ToArray, чтобы получить массив, содержащий объекты Customer.
Наконец, в последний раз выполняется перечисление последовательности сущностных объектов Customer с выводом на консоль их свойств CustomerID, Region и Country, чтобы доказать, что поле Country на самом деле было обновлено из базы данных.
Разумеется, придется также восстановить базу данных в исходное состояние, поэтому используется ADO.NET, чтобы установить Country заказчика обратно в исходное значение:
// Используйте свое подключение
Northwind db = new Northwind(@"Data Source=MICROSOF-1EA29E\SQLEXPRESS;
Initial Catalog=C:\NORTHWIND.MDF;
Integrated Security=True");
IEnumerable<Customer> custs = (from c in db.Customers
where c.Region == "WA"
select c);
Console.WriteLine("Сущностные объекты перед изменением:");
foreach (Customer c in custs)
{
Console.WriteLine("Заказчик {0} имеет регион {1} и страну {2}.",
c.CustomerID, c.Region, c.Country);
}
Console.WriteLine("\nОбновление страны этих заказчиков в базе данных, посредством ADO.NET...");
ExecuteStatementInDb(String.Format(
@"update Customers set Country = 'Russia' where Region = 'WA'"));
Console.WriteLine("Страна заказчиков обновлена.{0}", System.Environment.NewLine);
Console.WriteLine("Сущностные объекты после изменения с помощью ADO.NET, но без вызова метода Refresh():");
foreach (Customer c in custs)
{
Console.WriteLine("Заказчик {0} имеет регион {1} и страну {2}.",
c.CustomerID, c.Region, c.Country);
}
Customer[] custArray = custs.ToArray();
Console.WriteLine("\nОбновление массива, содержащего сущностные объекты заказчиков ...");
db.Refresh(RefreshMode.KeepChanges, custArray[0], custArray[1], custArray[2]);
Console.WriteLine("Массив обновлён.{0}",
System.Environment.NewLine);
Console.WriteLine("Сущностные объекты после изменения с помощью ADO.NET и вызова метода Refresh():");
foreach (Customer c in custs)
{
Console.WriteLine("Заказчик {0} имеет регион {1} и страну {2}.",
c.CustomerID, c.Region, c.Country);
}
ExecuteStatementInDb(String.Format(
@"update Customers set Country = 'USA' where Region = 'WA'"));
В предыдущем коде не происходит ничего интересного вплоть до момента вызова операции ToArray. Как только получается массив объектов Customer, сразу же вызывается RefreshMethod с передачей ему custArray[0], custArray[1] и custArray[2]. Взглянем на результаты:
В этом результате видно, что изменения, внесенные в поле Country в базе данных, не отражаются в сущностном объекте Customer до тех пор, пока не будет вызван метод Refresh.
В этом коде каждый обновленный сущностный объект был одного и того же типа — Customer. Во втором прототипе метода Refresh не обязательно, чтобы все переданные сущностные объекты были одного и того же типа. Ему можно передавать сущностные объекты разных типов.