Пошаговое руководство по самостоятельному отслеживанию сущностей
Важно!
Больше не рекомендуется использовать шаблон сущностей с самостоятельным отслеживанием. Он по-прежнему будет доступен только для поддержки существующих приложений. Если приложению необходимо работать с отключенными графами сущностей, рассмотрите другие варианты, такие как отслеживаемые сущности, которые технологически эквивалентны сущностям с самостоятельным отслеживанием, активно разрабатываемым сообществом. Или остановитесь на написании пользовательского кода с помощью API-интерфейсов отслеживания изменений низкого уровня.
В этом пошаговом руководстве демонстрируется сценарий, в котором служба Windows Communication Foundation (WCF) предоставляет операцию, которая возвращает граф сущностей. Затем клиентское приложение управляет этим графом и отправляет изменения в операцию службы, которая проверяет и сохраняет обновления базы данных с помощью Entity Framework.
Перед выполнением этого пошагового руководства убедитесь, что вы прочитали страницу сущностей самостоятельного отслеживания.
В этом пошаговом руководстве выполняются следующие действия.
- Создает базу данных для доступа.
- Создает библиотеку классов, содержащую модель.
- Переключение на шаблон генератора сущностей самостоятельного отслеживания.
- Перемещает классы сущностей в отдельный проект.
- Создает службу WCF, которая предоставляет операции для запроса и сохранения сущностей.
- Создает клиентские приложения (консоль и WPF), которые используют службу.
Мы будем использовать базу данных First в этом пошаговом руководстве, но те же методы применяются одинаково к модели First.
Для выполнения этого пошагового руководства потребуется последняя версия Visual Studio.
Сервер базы данных, установленный с Visual Studio, отличается в зависимости от установленной версии Visual Studio:
- Если вы используете Visual Studio 2012, вы создадите базу данных LocalDB.
- Если вы используете Visual Studio 2010, вы создадите базу данных SQL Express.
Давайте пойдем вперед и создадим базу данных.
- Запустите Visual Studio
- Представление —> Обозреватель сервера
- Щелкните правой кнопкой мыши данные Подключение ions—> добавьте Подключение ion...
- Если вы еще не подключились к базе данных из сервера Обозреватель, прежде чем выбрать Microsoft SQL Server в качестве источника данных
- Подключение в LocalDB или SQL Express в зависимости от установленного экземпляра
- Введите STESample в качестве имени базы данных
- Нажмите кнопку "ОК ", и вам будет предложено создать новую базу данных, нажмите кнопку "Да"
- Теперь новая база данных появится в сервере Обозреватель
- Если вы используете Visual Studio 2012
- Щелкните правой кнопкой мыши базу данных на сервере Обозреватель и выберите "Создать запрос"
- Скопируйте следующий SQL в новый запрос, а затем щелкните правой кнопкой мыши запрос и выберите "Выполнить".
- Если вы используете Visual Studio 2010
- Выбор данных —> редактор Transact SQL —> создание Подключение запроса...
- Введите .\SQLEXPRESS в качестве имени сервера и нажмите кнопку "ОК"
- Выберите базу данных STESample в раскрывающемся списке в верхней части редактора запросов.
- Скопируйте следующий SQL в новый запрос, а затем щелкните правой кнопкой мыши запрос и выберите "Выполнить SQL"
CREATE TABLE [dbo].[Blogs] (
[BlogId] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (200) NULL,
[Url] NVARCHAR (200) NULL,
CONSTRAINT [PK_dbo.Blogs] PRIMARY KEY CLUSTERED ([BlogId] ASC)
);
CREATE TABLE [dbo].[Posts] (
[PostId] INT IDENTITY (1, 1) NOT NULL,
[Title] NVARCHAR (200) NULL,
[Content] NTEXT NULL,
[BlogId] INT NOT NULL,
CONSTRAINT [PK_dbo.Posts] PRIMARY KEY CLUSTERED ([PostId] ASC),
CONSTRAINT [FK_dbo.Posts_dbo.Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [dbo].[Blogs] ([BlogId]) ON DELETE CASCADE
);
SET IDENTITY_INSERT [dbo].[Blogs] ON
INSERT INTO [dbo].[Blogs] ([BlogId], [Name], [Url]) VALUES (1, N'ADO.NET Blog', N'blogs.msdn.com/adonet')
SET IDENTITY_INSERT [dbo].[Blogs] OFF
INSERT INTO [dbo].[Posts] ([Title], [Content], [BlogId]) VALUES (N'Intro to EF', N'Interesting stuff...', 1)
INSERT INTO [dbo].[Posts] ([Title], [Content], [BlogId]) VALUES (N'What is New', N'More interesting stuff...', 1)
Во-первых, нам нужен проект, в который будет помещена модель.
- Файл —> создать проект> ...
- Выберите Visual C# в левой области, а затем библиотеку классов
- Введите STESample в качестве имени и нажмите кнопку "ОК"
Теперь мы создадим простую модель в ef Designer для доступа к нашей базе данных:
- Проект —> добавление нового элемента...
- Выберите данные из левой области, а затем ADO.NET модель данных сущности
- Введите bloggingModel в качестве имени и нажмите кнопку "ОК"
- Выберите " Создать из базы данных " и нажмите кнопку "Далее"
- Введите сведения о подключении для базы данных, созданной в предыдущем разделе
- Введите BloggingContext в качестве имени строка подключения и нажмите кнопку "Далее"
- Установите флажок рядом с таблицами и нажмите кнопку "Готово"
Теперь необходимо отключить создание кода по умолчанию и переключиться на сущности самостоятельного отслеживания.
- Разверните bloggingModel.edmx в Обозреватель решений и удалите BloggingModel.tt и BloggingModel.Context.ttэто приведет к отключению создания кода по умолчанию
- Щелкните правой кнопкой мыши пустую область в области EF Designer и выберите " Добавить элемент создания кода".
- Выберите "Online" в левой области и найдите генератор STE
- Выберите шаблон STE Generator for C#, введите STETemplate в качестве имени и нажмите кнопку "Добавить".
- Файлы STETemplate.tt и STETemplate.Context.tt добавляются в файл BloggingModel.edmx
- Щелкните правой кнопкой мыши пустую область в области EF Designer и выберите " Добавить элемент создания кода".
- Выберите код в левой области, а затем ADO.NET генератор сущностей самостоятельного отслеживания
- Введите STETemplate в качестве имени и нажмите кнопку "Добавить"
- Файлы STETemplate.tt и STETemplate.Context.tt добавляются непосредственно в проект
Чтобы использовать сущности самостоятельного отслеживания, нашим клиентским приложением необходим доступ к классам сущностей, созданным из нашей модели. Так как мы не хотим предоставлять всю модель клиентскому приложению, мы переместим классы сущностей в отдельный проект.
Первым шагом является остановка создания классов сущностей в существующем проекте:
- Щелкните правой кнопкой мыши STETemplate.tt в Обозреватель решений и выберите пункт "Свойства"
- В окне свойств снимите флажок TextTemplatingFileGenerator из свойства CustomTool
- Разверните STETemplate.tt в Обозреватель решений и удалите все файлы, вложенные в него
Далее мы добавим новый проект и создадим классы сущностей в нем
Файл —> добавление —> проект...
Выберите Visual C# в левой области, а затем библиотеку классов
Введите имя STESample.Entities и нажмите кнопку ОК
Проект —> добавление существующего элемента...
Перейдите в папку проекта STESample
Выберите, чтобы просмотреть все файлы (*.*)
Выберите файл STETemplate.tt
Щелкните стрелку раскрывающегося списка рядом с кнопкой "Добавить " и нажмите кнопку "Добавить как ссылку"
Мы также собираемся убедиться, что классы сущностей создаются в том же пространстве имен, что и контекст. Это просто сокращает количество инструкций использования, которые необходимо добавить во всем приложении.
- Щелкните правой кнопкой мыши связанный STETemplate.tt в Обозреватель решений и выберите "Свойства"
- В окне "Свойства" для настраиваемого пространства имен средства задано значение STESample
Для компиляции кода, созданного шаблоном STE, потребуется ссылка на System.Runtime.Serialization . Эта библиотека необходима для атрибутов WCF DataContract и DataMember , используемых для сериализуемых типов сущностей.
- Щелкните правой кнопкой мыши проект STESample.Entities в Обозреватель решений и выберите "Добавить ссылку...
- В Visual Studio 2012 — проверка поле рядом с System.Runtime.Serialization и нажмите кнопку ОК
- В Visual Studio 2010 выберите System.Runtime.Serialization и нажмите кнопку ОК
Наконец, проект с нашим контекстом в нем потребуется ссылка на типы сущностей.
- Щелкните правой кнопкой мыши проект STESample в Обозреватель решений и выберите "Добавить ссылку...
- В Visual Studio 2012 выберите решение в левой области, проверка поле рядом с STESample.Entities и нажмите кнопку "ОК"
- В Visual Studio 2010 выберите вкладку "Проекты ", выберите STESample.Entities и нажмите кнопку "ОК"
Примечание
Другим вариантом перемещения типов сущностей в отдельный проект является перемещение файла шаблона, а не связывание его из расположения по умолчанию. При этом необходимо обновить переменную inputFile в шаблоне, чтобы указать относительный путь к edmx-файлу (в этом примере это будет .). \BloggingModel.edmx).
Теперь пришло время добавить службу WCF для предоставления наших данных, мы начнем с создания проекта.
- Файл —> добавление —> проект...
- Выберите Visual C# в левой области, а затем приложение службы WCF
- Введите имя STESample.Service и нажмите кнопку ОК
- Добавление ссылки на сборку System.Data.Entity
- Добавление ссылки на проекты STESample и STESample.Entities
Необходимо скопировать ef строка подключения в этот проект, чтобы он был найден во время выполнения.
- Откройте файл App.Config для проекта **STESample *** и скопируйте элемент connectionStrings
- Вставьте элемент connectionStrings в качестве дочернего элемента конфигурации файла Web.Config в проекте STESample.Service
Теперь пришло время реализовать фактическую службу.
- Откройте файл IService1.cs и замените содержимое следующим кодом.
using System.Collections.Generic;
using System.ServiceModel;
namespace STESample.Service
{
[ServiceContract]
public interface IService1
{
[OperationContract]
List<Blog> GetBlogs();
[OperationContract]
void UpdateBlog(Blog blog);
}
}
- Откройте Service1.svc и замените содержимое следующим кодом.
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
namespace STESample.Service
{
public class Service1 : IService1
{
/// <summary>
/// Gets all the Blogs and related Posts.
/// </summary>
public List<Blog> GetBlogs()
{
using (BloggingContext context = new BloggingContext())
{
return context.Blogs.Include("Posts").ToList();
}
}
/// <summary>
/// Updates Blog and its related Posts.
/// </summary>
public void UpdateBlog(Blog blog)
{
using (BloggingContext context = new BloggingContext())
{
try
{
// TODO: Perform validation on the updated order before applying the changes.
// The ApplyChanges method examines the change tracking information
// contained in the graph of self-tracking entities to infer the set of operations
// that need to be performed to reflect the changes in the database.
context.Blogs.ApplyChanges(blog);
context.SaveChanges();
}
catch (UpdateException)
{
// To avoid propagating exception messages that contain sensitive data to the client tier
// calls to ApplyChanges and SaveChanges should be wrapped in exception handling code.
throw new InvalidOperationException("Failed to update. Try your request again.");
}
}
}
}
}
Создадим консольное приложение, использующее нашу службу.
- Файл —> создать проект> ...
- Выберите Visual C# в левой области, а затем консольное приложение
- Введите STESample.ConsoleTest в качестве имени и нажмите кнопку "ОК"
- Добавление ссылки на проект STESample.Entities
Нам нужна ссылка на службу WCF
- Щелкните правой кнопкой мыши проект STESample.ConsoleTest в Обозреватель решений и выберите команду Добавить ссылку на службу...
- Нажмите кнопку " Обнаружить"
- Введите BloggingService в качестве пространства имен и нажмите кнопку "ОК"
Теперь можно написать код для использования службы.
- Откройте Program.cs и замените содержимое следующим кодом.
using STESample.ConsoleTest.BloggingService;
using System;
using System.Linq;
namespace STESample.ConsoleTest
{
class Program
{
static void Main(string[] args)
{
// Print out the data before we change anything
Console.WriteLine("Initial Data:");
DisplayBlogsAndPosts();
// Add a new Blog and some Posts
AddBlogAndPost();
Console.WriteLine("After Adding:");
DisplayBlogsAndPosts();
// Modify the Blog and one of its Posts
UpdateBlogAndPost();
Console.WriteLine("After Update:");
DisplayBlogsAndPosts();
// Delete the Blog and its Posts
DeleteBlogAndPost();
Console.WriteLine("After Delete:");
DisplayBlogsAndPosts();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
static void DisplayBlogsAndPosts()
{
using (var service = new Service1Client())
{
// Get all Blogs (and Posts) from the service
// and print them to the console
var blogs = service.GetBlogs();
foreach (var blog in blogs)
{
Console.WriteLine(blog.Name);
foreach (var post in blog.Posts)
{
Console.WriteLine(" - {0}", post.Title);
}
}
}
Console.WriteLine();
Console.WriteLine();
}
static void AddBlogAndPost()
{
using (var service = new Service1Client())
{
// Create a new Blog with a couple of Posts
var newBlog = new Blog
{
Name = "The New Blog",
Posts =
{
new Post { Title = "Welcome to the new blog"},
new Post { Title = "What's new on the new blog"}
}
};
// Save the changes using the service
service.UpdateBlog(newBlog);
}
}
static void UpdateBlogAndPost()
{
using (var service = new Service1Client())
{
// Get all the Blogs
var blogs = service.GetBlogs();
// Use LINQ to Objects to find The New Blog
var blog = blogs.First(b => b.Name == "The New Blog");
// Update the Blogs name
blog.Name = "The Not-So-New Blog";
// Update one of the related posts
blog.Posts.First().Content = "Some interesting content...";
// Save the changes using the service
service.UpdateBlog(blog);
}
}
static void DeleteBlogAndPost()
{
using (var service = new Service1Client())
{
// Get all the Blogs
var blogs = service.GetBlogs();
// Use LINQ to Objects to find The Not-So-New Blog
var blog = blogs.First(b => b.Name == "The Not-So-New Blog");
// Mark all related Posts for deletion
// We need to call ToList because each Post will be removed from the
// Posts collection when we call MarkAsDeleted
foreach (var post in blog.Posts.ToList())
{
post.MarkAsDeleted();
}
// Mark the Blog for deletion
blog.MarkAsDeleted();
// Save the changes using the service
service.UpdateBlog(blog);
}
}
}
}
Теперь вы можете запустить приложение и увидеть, как оно работает:
- Щелкните правой кнопкой мыши проект STESample.ConsoleTest в Обозреватель решений и выберите "Отладка — Запуск нового экземпляра">
При выполнении приложения вы увидите следующие выходные данные.
Initial Data:
ADO.NET Blog
- Intro to EF
- What is New
After Adding:
ADO.NET Blog
- Intro to EF
- What is New
The New Blog
- Welcome to the new blog
- What's new on the new blog
After Update:
ADO.NET Blog
- Intro to EF
- What is New
The Not-So-New Blog
- Welcome to the new blog
- What's new on the new blog
After Delete:
ADO.NET Blog
- Intro to EF
- What is New
Press any key to exit...
Создадим приложение WPF, использующее нашу службу.
- Файл —> создать проект> ...
- Выберите Visual C# в левой области, а затем приложение WPF
- Введите STESample.WPFTest в качестве имени и нажмите кнопку "ОК"
- Добавление ссылки на проект STESample.Entities
Нам нужна ссылка на службу WCF
- Щелкните правой кнопкой мыши проект STESample.WPFTest в Обозреватель решений и выберите команду Добавить ссылку на службу...
- Нажмите кнопку " Обнаружить"
- Введите BloggingService в качестве пространства имен и нажмите кнопку "ОК"
Теперь можно написать код для использования службы.
- Откройте MainWindow.xaml и замените содержимое следующим кодом.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:STESample="clr-namespace:STESample;assembly=STESample.Entities"
mc:Ignorable="d" x:Class="STESample.WPFTest.MainWindow"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
<CollectionViewSource
x:Key="blogViewSource"
d:DesignSource="{d:DesignInstance {x:Type STESample:Blog}, CreateList=True}"/>
<CollectionViewSource
x:Key="blogPostsViewSource"
Source="{Binding Posts, Source={StaticResource blogViewSource}}"/>
</Window.Resources>
<Grid DataContext="{StaticResource blogViewSource}">
<DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
ItemsSource="{Binding}" Margin="10,10,10,179">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding BlogId}" Header="Id" Width="Auto" IsReadOnly="True" />
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="Auto"/>
<DataGridTextColumn Binding="{Binding Url}" Header="Url" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
ItemsSource="{Binding Source={StaticResource blogPostsViewSource}}" Margin="10,145,10,38">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding PostId}" Header="Id" Width="Auto" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding Title}" Header="Title" Width="Auto"/>
<DataGridTextColumn Binding="{Binding Content}" Header="Content" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
<Button Width="68" Height="23" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Margin="0,0,10,10" Click="buttonSave_Click">Save</Button>
</Grid>
</Window>
- Откройте код для MainWindow (MainWindow.xaml.cs) и замените содержимое следующим кодом.
using STESample.WPFTest.BloggingService;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Data;
namespace STESample.WPFTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
using (var service = new Service1Client())
{
// Find the view source for Blogs and populate it with all Blogs (and related Posts)
// from the Service. The default editing functionality of WPF will allow the objects
// to be manipulated on the screen.
var blogsViewSource = (CollectionViewSource)this.FindResource("blogViewSource");
blogsViewSource.Source = service.GetBlogs().ToList();
}
}
private void buttonSave_Click(object sender, RoutedEventArgs e)
{
using (var service = new Service1Client())
{
// Get the blogs that are bound to the screen
var blogsViewSource = (CollectionViewSource)this.FindResource("blogViewSource");
var blogs = (List<Blog>)blogsViewSource.Source;
// Save all Blogs and related Posts
foreach (var blog in blogs)
{
service.UpdateBlog(blog);
}
// Re-query for data to get database-generated keys etc.
blogsViewSource.Source = service.GetBlogs().ToList();
}
}
}
}
Теперь вы можете запустить приложение и увидеть, как оно работает:
- Щелкните правой кнопкой мыши проект STESample.WPFTest в Обозреватель решений и выберите "Отладка — запуск нового экземпляра">
- Вы можете управлять данными с помощью экрана и сохранять их с помощью службы с помощью кнопки "Сохранить "
Отзыв о .NET
.NET — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв: