Введение в облачные решения Microsoft

Хранилище данных с реляционной структурой

Разбить на страницы
Показывать лекцию целиком

Как мы уже говорили в лекциях, хранилище Windows Azure, помимо прочего, подходит для хранения реляционных данных, для этого используются возможности Windows Azure Table. Однако, само по себе, табличное хранилище Windows Azure не хранит данные в реляционном виде. Возникает вопрос, каким образом возможно хранить реляционную структуру и как обеспечить миграцию данных?

Ответов на данные вопросы может быть множество. То как вы решите переносить существующую реляционную структуру данных в облако, зависит целиком от вас самих. Мы продемонстрируем самый простой и очевидный способ - построчное чтение данных из реляционной БД и запись их в таблицу Windows Azure, что и будет целью данной практической работы.

Во-первых, нам понадобится реляционная база данных. В нашей базе будут храниться 3 взаимосвязанные сущности - Адрес, Фирма и Сотрудник.

В данной лабораторной работе мы использовали SQL Management Studio для соединения с базой sqlexpress и выполнения запросов.

Создадим базу данных при помощи запроса 16.1

create database azureexample

Теперь необходимо создать таблицы, связи между ними и заполнить их тестовым набором данных. Вы можете проделать это самостоятельно, а можно просто выполнить нижеследующий зарос:

use azureexample

create table Address(
AddresID int identity(1,1) primary key,
Country nvarchar(max),
City nvarchar(max),
Street nvarchar(max),
House int
)

create table Firm(
FirmID int identity(1,1) primary key,
NameOf nvarchar(max),
Telephone nvarchar(10),
Email nvarchar(max),
AddressKey int not null
)

create table Employee(
EmployeeID int identity(1,1) primary key,
FirstName nvarchar(max),
LastName nvarchar(max),
Telephone nvarchar(10),
FirmKey int
)

Alter table dbo.Firm add constraint
  FK_Firm_Address foreign key
  (
  AddressKey
  ) references dbo.Address
  (
  AddresID
  ) on update no action 
   On delete no action 
   
alter table dbo.Employee add constraint
FK_Employee_Firm foreign key
(
FirmKey
)
references dbo.Firm
(
FirmID
)
on update no action
on delete no action

insert into Address
values ('RF', 'Tomsk', 'Evergreen Terrace', '247')

insert into Firm
values ('Firm1', 'xxx-xx-xx', 'firm1@testmail.com', '1')

insert into Firm
values ('Firm2', 'xxx-xx-xx', 'firm2@testmail.com', '1')

insert into Employee
values ('Ivan', 'Ivanov', 'x-xxx-xx','1')

insert into Employee
values ('Victor', 'Romanov', 'x-xxx-xx','1')

insert into Employee
values ('Alex', 'Petrov', 'x-xxx-xx','2')

Таким образом мы получили три таблицы. Диаграмма данных созданной базы представлена ниже:

(рис 16.1)

Теперь необходимо решить, каким образом данная реляционная структура может быть перенесена в таблицу. Как вам известно из лекции, таблицу Windows Azure можно соотнести с коллекцией взаимосвязанных сущностей, если проводить аналогии с реляционными базами данных. В то время, как строки таблиц Windows Azure, по сути являются экземплярами конкретных сущностей.

Мы предлагаем следующее очевидное решение:

Создать Windows Azure таблицу "Relational", которая будет содержать в себе сущности Address, Firm и Employee

Ключ секции будет указывать на соответствие строки таблицы Azure экземпляру сущности реляционной БД, т.е. для всех сотрудников ключ секции будет - "Employee"

Значения атрибутов - ключей в реляционных таблицах будут являться значениями RowKey для таблицы "Relational", такими образом пара ключ секции - ключ строки будет являться уникальным идентификатором однозначно указывающим на принадлежность Azure - строки конкретной сущности исходной БД и определяющим экземпляр сущности

Значения остальных атрибутов будут перенесены без изменений.

Мы не видим необходимости в создании нового VS - проекта, поэтому просто изменим WorkerRole.cs проекта, созданного в рамках предыдущей практической работы. А именно, метод Run, чей листинг представлен ниже:

CloudStorageAccount.SetConfigurationSettingPublisher(
                (configName, configSettingPublisher) =>
                {
                    var connectionString =
                        RoleEnvironment.GetConfigurationSettingValue(configName);
                    configSettingPublisher(connectionString);
                }
            );

            CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

            //создание таблицы Windows Azure Table
            CloudTableClient _tc = null;
            _tc = account.CreateCloudTableClient();
            _tc.CreateTableIfNotExist("Relational");
            Context context = new Context(account.TableEndpoint, account.Credentials);
            //определение параметров подключения к БД, измените строку подключения 
            //соответствующим образом, для соединения с вашим sql - сервером
            SqlConnection conn = new SqlConnection("Data Source=saigon\\sqlexpress; 
              Initial Catalog=azureexample; Integrated Security=true;");

            //импорт данных из таблицы Address
            //указываем команду для чтения данных из базы
            SqlCommand cmd = new SqlCommand("SELECT * FROM Address", conn);
            conn.Open();
            SqlDataReader adr = cmd.ExecuteReader();
            while (adr.Read())
            {
//в параметрах метода AddObject указывает имя таблицы и определяем новую сущность класс //Address
                context.AddObject("Relational", new Address
                {
                    PartitionKey = "Address",
                    RowKey = adr["AddresID"].ToString(),
                    country = adr["Country"].ToString(),
                    city = adr["City"].ToString(),
                    street = adr["Street"].ToString(),
                    house = Convert.ToInt32(adr["House"].ToString())
                });
                context.SaveChanges();
            }
            adr.Close();
//импорт данных из таблицы Firm
            cmd.CommandText = "SELECT * FROM Firm";
            SqlDataReader frm = cmd.ExecuteReader();
            while (frm.Read())
            {
                context.AddObject("Relational", new Firm
                {
                    PartitionKey = "Firm",
                    RowKey = frm["FirmID"].ToString(),
                    nameof = frm["NameOf"].ToString(),
                    telephone = frm["Telephone"].ToString(),
                    email = frm["Email"].ToString(),
                    adresskey = Convert.ToInt32(frm["AddressKey"].ToString())
                });
                context.SaveChanges();
            }
            frm.Close();
//импорт данных из таблицы Employee
            cmd.CommandText = "SELECT * FROM Employee";
            SqlDataReader emp = cmd.ExecuteReader();
            while (emp.Read())
            {
                context.AddObject("Relational", new Employee
                {
                    PartitionKey = "Employee",
                    RowKey = emp["EmployeeID"].ToString(),
                    firstname = emp["FirstName"].ToString(),
                    lastname = emp["LastName"].ToString(),
                    telephone = emp["Telephone"].ToString(),
                    firmkey = Convert.ToInt32(emp["FirmKey"].ToString())
                });
                context.SaveChanges();
            }
            emp.Close();

            conn.Close();

Кроме того, нам необходимо создать классы - соответствующие сущностям реляционной базы данных, а также класс - контекст.

Класс Address.cs

class Address: TableServiceEntity
    {
        public String country { get; set; }
        public String city { get; set; }
        public String street { get; set; }
        public int house { get; set; }
    }

Класс Firm.cs

class Firm: TableServiceEntity
    {
        public String nameof { get; set; }
        public String telephone { get; set; }
        public String email { get; set; }
        public int adresskey { get; set; }
    }

Класс Employee.cs

class Employee: TableServiceEntity
    {
        public String firstname { get; set; }
        public String lastname { get; set; }
        public String telephone { get; set;}
        public int firmkey { get; set; }
    }

Класс Context.cs

class Context: TableServiceContext
    {
            public IQueryable<Address> ContactData
            {
                get
                {
                    return this.CreateQuery<Address>("Address");

                }
            }
            public Context(Uri baseAddress, StorageCredentials credentials) : 
                  base(baseAddress.AbsoluteUri, credentials) { }
        }

Запустите приложение и дождитесь конца его выполнения. В обозревателе серверов раскройте вкладку "Хранилище Windows Azure", затем обновите вкладку "Таблицы" и раскройте ее. Как вы можете видеть, появилась таблица "Relational".

(рис 16.2)

Если вы решите ее просмотреть, то увидите, что данные из реляционной БД успешно перенесены в таблицу.

(рис 16.3)
Страницы:

Как мы уже говорили в лекциях, хранилище Windows Azure, помимо прочего, подходит для хранения реляционных данных, для этого используются возможности Windows Azure Table. Однако, само по себе, табличное хранилище Windows Azure не хранит данные в реляционном виде. Возникает вопрос, каким образом возможно хранить реляционную структуру и как обеспечить миграцию данных?

Ответов на данные вопросы может быть множество. То как вы решите переносить существующую реляционную структуру данных в облако, зависит целиком от вас самих. Мы продемонстрируем самый простой и очевидный способ - построчное чтение данных из реляционной БД и запись их в таблицу Windows Azure, что и будет целью данной практической работы.

Во-первых, нам понадобится реляционная база данных. В нашей базе будут храниться 3 взаимосвязанные сущности - Адрес, Фирма и Сотрудник.

В данной лабораторной работе мы использовали SQL Management Studio для соединения с базой sqlexpress и выполнения запросов.

Создадим базу данных при помощи запроса 16.1

create database azureexample

Теперь необходимо создать таблицы, связи между ними и заполнить их тестовым набором данных. Вы можете проделать это самостоятельно, а можно просто выполнить нижеследующий зарос:

use azureexample

create table Address(
AddresID int identity(1,1) primary key,
Country nvarchar(max),
City nvarchar(max),
Street nvarchar(max),
House int
)

create table Firm(
FirmID int identity(1,1) primary key,
NameOf nvarchar(max),
Telephone nvarchar(10),
Email nvarchar(max),
AddressKey int not null
)

create table Employee(
EmployeeID int identity(1,1) primary key,
FirstName nvarchar(max),
LastName nvarchar(max),
Telephone nvarchar(10),
FirmKey int
)

Alter table dbo.Firm add constraint
  FK_Firm_Address foreign key
  (
  AddressKey
  ) references dbo.Address
  (
  AddresID
  ) on update no action 
   On delete no action 
   
alter table dbo.Employee add constraint
FK_Employee_Firm foreign key
(
FirmKey
)
references dbo.Firm
(
FirmID
)
on update no action
on delete no action

insert into Address
values ('RF', 'Tomsk', 'Evergreen Terrace', '247')

insert into Firm
values ('Firm1', 'xxx-xx-xx', 'firm1@testmail.com', '1')

insert into Firm
values ('Firm2', 'xxx-xx-xx', 'firm2@testmail.com', '1')

insert into Employee
values ('Ivan', 'Ivanov', 'x-xxx-xx','1')

insert into Employee
values ('Victor', 'Romanov', 'x-xxx-xx','1')

insert into Employee
values ('Alex', 'Petrov', 'x-xxx-xx','2')

Таким образом мы получили три таблицы. Диаграмма данных созданной базы представлена ниже:

(рис 16.1)

Теперь необходимо решить, каким образом данная реляционная структура может быть перенесена в таблицу. Как вам известно из лекции, таблицу Windows Azure можно соотнести с коллекцией взаимосвязанных сущностей, если проводить аналогии с реляционными базами данных. В то время, как строки таблиц Windows Azure, по сути являются экземплярами конкретных сущностей.

Мы предлагаем следующее очевидное решение:

Создать Windows Azure таблицу "Relational", которая будет содержать в себе сущности Address, Firm и Employee

Ключ секции будет указывать на соответствие строки таблицы Azure экземпляру сущности реляционной БД, т.е. для всех сотрудников ключ секции будет - "Employee"

Значения атрибутов - ключей в реляционных таблицах будут являться значениями RowKey для таблицы "Relational", такими образом пара ключ секции - ключ строки будет являться уникальным идентификатором однозначно указывающим на принадлежность Azure - строки конкретной сущности исходной БД и определяющим экземпляр сущности

Значения остальных атрибутов будут перенесены без изменений.

Мы не видим необходимости в создании нового VS - проекта, поэтому просто изменим WorkerRole.cs проекта, созданного в рамках предыдущей практической работы. А именно, метод Run, чей листинг представлен ниже:

CloudStorageAccount.SetConfigurationSettingPublisher(
                (configName, configSettingPublisher) =>
                {
                    var connectionString =
                        RoleEnvironment.GetConfigurationSettingValue(configName);
                    configSettingPublisher(connectionString);
                }
            );

            CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

            //создание таблицы Windows Azure Table
            CloudTableClient _tc = null;
            _tc = account.CreateCloudTableClient();
            _tc.CreateTableIfNotExist("Relational");
            Context context = new Context(account.TableEndpoint, account.Credentials);
            //определение параметров подключения к БД, измените строку подключения 
            //соответствующим образом, для соединения с вашим sql - сервером
            SqlConnection conn = new SqlConnection("Data Source=saigon\\sqlexpress; 
              Initial Catalog=azureexample; Integrated Security=true;");

            //импорт данных из таблицы Address
            //указываем команду для чтения данных из базы
            SqlCommand cmd = new SqlCommand("SELECT * FROM Address", conn);
            conn.Open();
            SqlDataReader adr = cmd.ExecuteReader();
            while (adr.Read())
            {
//в параметрах метода AddObject указывает имя таблицы и определяем новую сущность класс //Address
                context.AddObject("Relational", new Address
                {
                    PartitionKey = "Address",
                    RowKey = adr["AddresID"].ToString(),
                    country = adr["Country"].ToString(),
                    city = adr["City"].ToString(),
                    street = adr["Street"].ToString(),
                    house = Convert.ToInt32(adr["House"].ToString())
                });
                context.SaveChanges();
            }
            adr.Close();
//импорт данных из таблицы Firm
            cmd.CommandText = "SELECT * FROM Firm";
            SqlDataReader frm = cmd.ExecuteReader();
            while (frm.Read())
            {
                context.AddObject("Relational", new Firm
                {
                    PartitionKey = "Firm",
                    RowKey = frm["FirmID"].ToString(),
                    nameof = frm["NameOf"].ToString(),
                    telephone = frm["Telephone"].ToString(),
                    email = frm["Email"].ToString(),
                    adresskey = Convert.ToInt32(frm["AddressKey"].ToString())
                });
                context.SaveChanges();
            }
            frm.Close();
//импорт данных из таблицы Employee
            cmd.CommandText = "SELECT * FROM Employee";
            SqlDataReader emp = cmd.ExecuteReader();
            while (emp.Read())
            {
                context.AddObject("Relational", new Employee
                {
                    PartitionKey = "Employee",
                    RowKey = emp["EmployeeID"].ToString(),
                    firstname = emp["FirstName"].ToString(),
                    lastname = emp["LastName"].ToString(),
                    telephone = emp["Telephone"].ToString(),
                    firmkey = Convert.ToInt32(emp["FirmKey"].ToString())
                });
                context.SaveChanges();
            }
            emp.Close();

            conn.Close();

Кроме того, нам необходимо создать классы - соответствующие сущностям реляционной базы данных, а также класс - контекст.

Класс Address.cs

class Address: TableServiceEntity
    {
        public String country { get; set; }
        public String city { get; set; }
        public String street { get; set; }
        public int house { get; set; }
    }

Класс Firm.cs

class Firm: TableServiceEntity
    {
        public String nameof { get; set; }
        public String telephone { get; set; }
        public String email { get; set; }
        public int adresskey { get; set; }
    }

Класс Employee.cs

class Employee: TableServiceEntity
    {
        public String firstname { get; set; }
        public String lastname { get; set; }
        public String telephone { get; set;}
        public int firmkey { get; set; }
    }

Класс Context.cs

class Context: TableServiceContext
    {
            public IQueryable<Address> ContactData
            {
                get
                {
                    return this.CreateQuery<Address>("Address");

                }
            }
            public Context(Uri baseAddress, StorageCredentials credentials) : 
                  base(baseAddress.AbsoluteUri, credentials) { }
        }

Запустите приложение и дождитесь конца его выполнения. В обозревателе серверов раскройте вкладку "Хранилище Windows Azure", затем обновите вкладку "Таблицы" и раскройте ее. Как вы можете видеть, появилась таблица "Relational".

(рис 16.2)

Если вы решите ее просмотреть, то увидите, что данные из реляционной БД успешно перенесены в таблицу.

(рис 16.3)
Вернуться к учебному плану