Метод Refresh()

31

»» В ДАННОЙ СТАТЬЕ ИСПОЛЬЗУЕТСЯ ИСХОДНЫЙ КОД ДЛЯ ПРИМЕРОВ

Метод 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 — значение, измененное в сущностном объекте.

И, наконец, исходные значения в базе данных восстанавливаются, чтобы этот пример можно было запустить снова, и чтобы последующие примеры сохранили работоспособность.

Ниже показаны результаты работы кода:

 Пример вызова первого прототипа метода Refresh

Как видите, сущностный объект не знает об изменении 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]. Взглянем на результаты:

Пример вызова второго прототипа метода Refresh

В этом результате видно, что изменения, внесенные в поле Country в базе данных, не отражаются в сущностном объекте Customer до тех пор, пока не будет вызван метод Refresh.

В этом коде каждый обновленный сущностный объект был одного и того же типа — Customer. Во втором прототипе метода Refresh не обязательно, чтобы все переданные сущностные объекты были одного и того же типа. Ему можно передавать сущностные объекты разных типов.

Пройди тесты
Лучший чат для C# программистов