Показаны сообщения с ярлыком Entity Framework. Показать все сообщения
Показаны сообщения с ярлыком Entity Framework. Показать все сообщения

четверг, 26 декабря 2013 г.

Использование паттернов Unit of work и Generic Repository c Entity Framework 5.0

Использование паттернов Unit of work и Generic Repository c Entity Framework 5.0
Паттерн Unit of Work, по сути, нужен для консолидации всех методов, которые работают с базой данных. С его помощью можно улучшить контроль над изменением данных в БД, а также оптимизировать использование БД при обработке нескольких запросов одновременно. Использование Generic Repository упростит работу с EF Entities.
Создаем интерфейс IRepository, который описывает все необходимые операции с БД:
public interface IRepository<TEntity>  where TEntity : class
    {
        IEnumerable<TEntity> Get();
        TEntity GetById(object id);
        void Insert(TEntity entity);
        void Delete(object id);
        void Delete(TEntity entityToDelete);
        void Update(TEntity entityToUpdate);
    }

понедельник, 19 августа 2013 г.

Database scan with Entity Framework (part 2 multithread).

В первой части я рассказал, как использовать EF 5.0 для задачи сканирования БД с целью выявления новых заданий. Однако в WPF такой подход в чистом виде применять нельзя из-за того, что задача сканирования базы данных должна постоянно выполняться в программе, а также она может занимать значительный промежуток времени. Это значит, что при синхронном ее выполнении в UI потоке, наше приложение практически постоянно будет находиться в режиме зависания, а это недопустимо. Решение этой задачи состоит в асинхронном выполнении задачи сканирования БД, с последующим выводом результатов в UI thread, так как только через UI thread мы можем менять состояние GUI. Программных реализаций такого решения много, тут я покажу использование асинхронной модели на основе задач (TAP) (.net framework 4.5) в сочетании с возможностями C# 5.0.
Асинхронный метод должен возвращать объект Task, Task<TResult>, или void. Хотя возвращать void рекомендуется только для обработчиков событий.
Перейдем непосредственно к программной реализации. Перед тем как запустить метод асинхронного сканирования БД, при первом запуске программы необходимо получить максимальный идентификатор записи в БД.

private void Application_Startup(object sender, StartupEventArgs e)
        {  
            var mainWindow = new MainWindow();
            Current.MainWindow = mainWindow;
            var viewModel = new MainViewModel(mainWindow);
            mainWindow.DataContext = viewModel;
            mainWindow.Tb = (TaskbarIcon)FindResource("NotifIcon");
            if (mainWindow.Tb != null) 
                mainWindow.Tb.DataContext = viewModel;
            //var trayToolTip = new UserControl1 {DataContext = viewModel};
            viewModel.GetId(); // получаем максимальный ID
            mainWindow.Show();
        }
public class MainViewModel : ViewModelBase
    {
      public void GetId()
             {
                  using (var context = new CCYCEntities())
                  {
                      LastEngineId = DataService.GetLastEngId(context).ToString(CultureInfo.InvariantCulture);
                  }
    }
class DataService
    {
        internal static long GetLastEngId(CCYCEntities context)
        {
            var tmp =
                (from eng in context.Engines orderby  eng.ID_Engine select eng.ID_Engine).ToList().LastOrDefault();
            return tmp;
        }
    }

После этого в классе DataService реализуем асинхронное сканирование БД:

class DataService
    {
        internal static Task'<'List'<'Engine'>''>' GetNewEnginesAsync( CCYCEntities context, long maxId, CancellationToken cancellationToken)
        {
            return Task.Run(() =>
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var tmp = (from d in context.Engines where d.ID_Engine > maxId select d).ToList();
                    return tmp;
                });
        }
}

Использование в MainViewModel:

private async void Test()
        {
            var ctn = new CancellationToken();
            using (var context = new CCYCEntities())
            {
  try
                {
                    while (true)
                    {
                        var rez = await DataService.GetNewEnginesAsync(context,_lastId,ctn);
                        await Task.Delay(3000);
                        TestAsync = rez.Count.ToString(CultureInfo.InvariantCulture);
                        _lastId +=  rez.Count();
                        LastEngineId = _lastId.ToString(CultureInfo.InvariantCulture);
                        var lastOrDefault = rez.LastOrDefault();
                        if (lastOrDefault != null)
                        {
                            var nameEng = lastOrDefault.NameEngine;
                            const string act = "was added";
                            Welcome = string.Format("{0} {1}", nameEng, act); 
                        }
                        else Welcome = "No new Engines";                    
                      }
Тут свойства LastEngineID, Welcome и void Test() связаны с соответствующими компонентами GUI WPF.

Полезные ссылки: 
1. MSDN
2. MSDN Magazine

понедельник, 24 июня 2013 г.

Database scan with Entity Framework (part 1 monothread)

При работе над одним проектом возникла задача асинхронного сканирования базы данных на предмет появления новых записей с последующей их обработкой. В качестве поставщика данных решено было использовать ORM Entity Framework 5.0, который активно продвигается в Microsoft. Далее рассмотрим основные подходы к использованию EF.
В EF для решения тех или иных задач используется три подхода:
  • Database first;
  • Model first;
  • Code first;
Так как у нас в проекте уже была база данных, написанная на SQL Server, был использован подход Database first. В кратце напомню его суть: по уже готовой базе данных EF строит модель классов, которые содержат ту же логику привязки данных, что и таблицы в базе данных, также создается контекст доступа к ним (класс-наследник от DbSet). Например, у нас есть таблица Engines:

CREATE TABLE Spacecrafts.Engine
 (
 ID_Engine int NULL CONSTRAINT UQ_ID_ENG UNIQUE,
 NameEngine nvarchar(50) NULL,
 Trust real NOT NULL,
 SpecificImpulse real NOT NULL,
 FuelAmount int NULL,
 MaxTimeOfWorking real NULL,
 TypeOfEngine nvarchar(50) NULL,
 Comment nvarchar(150) NULL
 )  ON [PRIMARY]
GO
для которой EF создает класс Engine с соответствующими свойствами:
public class SomeClass 
 public partial class Engine
    {
        public Engine()
        {
            this.SpacecraftCharacteristics = new HashSet();
        }
    
        public int ID_Engine { get; set; }
        public string NameEngine { get; set; }
        public float Trust { get; set; }
        public float SpecificImpulse { get; set; }
        public Nullable FuelAmount { get; set; }
        public Nullable MaxTimeOfWorking { get; set; }
        public string TypeOfEngine { get; set; }
        public string Comment { get; set; }
    
        public virtual ICollection SpacecraftCharacteristics { get; set; }
    }
Далее перейдем к непосредственной работе с этим классом: