Data Access Layer

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

Первым уровнем, который мы реализуем, будет Data Access Layer или уровень доступа к данным. Этот уровень обычно содержит все модели данных, хранящихся в БД, а также классы, через которые идет взаимодействие с БД. И вначале создадим новый проект ASP.NET MVC без аутентификации. При этом решение назовем NLayerApp, а проект NLayerApp.WEB:

N-Layer ASP.NET application

Проект NLayerApp.WEB будет представлять уровень представления.

После создания решения и проекта добавим в решение новый проект по типу Class Library, который назовем NLayerApp.DAL. Этот проект будет представлять уровень доступа к данным.

Первым делом определим модели, объекты которых будут храниться в бд. Для этого в проект добавим новую папку Entities, а в этой папке определим следующий класс модели Phone:

using System.Collections.Generic;

namespace NLayerApp.DAL.Entities
{
    public class Phone
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Company { get; set; }
        public decimal Price { get; set; }
        public ICollection<Order> Orders { get; set; }
    }
}

И модели Order:

using System;
namespace NLayerApp.DAL.Entities
{
    public class Order
    {
        public int Id { get; set; }
        public decimal Sum { get; set; }
        public string PhoneNumber { get; set; }
        public string Address { get; set; }

        public int PhoneId { get; set; }
        public Phone Phone { get; set; }

        public DateTime Date { get; set; }
    }
}

Теперь добавим в проект через NuGet пакет Entity Framework и также определим в проекте новую папку, которая пусть будет называться EF. В эту папку добавим класс контекста данных:

using System.Collections.Generic;
using System.Data.Entity;
using System.Threading.Tasks;
using NLayerApp.DAL.Entities;

namespace NLayerApp.DAL.EF
{
    public class MobileContext : DbContext
    {
        public DbSet<Phone> Phones { get; set; }
        public DbSet<Order> Orders { get; set; }

        static MobileContext()
        {
            Database.SetInitializer<MobileContext>(new StoreDbInitializer());
        }
        public MobileContext(string connectionString)
            : base(connectionString)
        {
        }
    }
    
    public class StoreDbInitializer : DropCreateDatabaseIfModelChanges<MobileContext>
    {
        protected override void Seed(MobileContext db)
        {
            db.Phones.Add(new Phone { Name = "Nokia Lumia 630", Company = "Nokia", Price = 220 });
            db.Phones.Add(new Phone { Name = "iPhone 6", Company = "Apple", Price = 320 });
            db.Phones.Add(new Phone { Name = "LG G4", Company = "lG", Price = 260 });
            db.Phones.Add(new Phone { Name = "Samsung Galaxy S 6", Company = "Samsung", Price = 300 });
            db.SaveChanges();
        }
    }
}

Как и в проекте с монолитной архитектурой здесь также используется инициализатор БД, который теперь выполняется в статическом конструкторе контекста. Кроме того, для строки подключения конструктор контекста принимает строковый параметр connectionString.

Для увеличения гибкости подключения к БД используются репозитории. Поэтому вначале определим в проекте еще одну папку Interfaces. И в нее добавим интерфейс репозиториев IRepository:

using System;
using System.Collections.Generic;

namespace NLayerApp.DAL.Interfaces
{
    public interface IRepository<T> where T : class
    {
        IEnumerable<T> GetAll();
        T Get(int id);
        IEnumerable<T> Find(Func<T, Boolean> predicate);
        void Create(T item);
        void Update(T item);
        void Delete(int id);
    }
}

Поскольку мы будем использовать несколько репозитория для каждой сущности, то для упрощения использования подключения к бд будем использовать паттерн Unit Of Work. И для этого также в папку Interfaces добавим новый интерфейс IUnitOfWork:

using NLayerApp.DAL.Entities;
using System;

namespace NLayerApp.DAL.Interfaces
{
    public interface IUnitOfWork : IDisposable
    {
        IRepository<Phone> Phones { get;}
        IRepository<Order> Orders { get;}
        void Save();
    }
}

Для хранения реализаций данных интерфейсов определим в проекте еще одну папку Repositories. Добавим в нее класс репозитория для смартфонов PhoneRepository:

using System;
using System.Collections.Generic;
using System.Linq;
using NLayerApp.DAL.Entities;
using NLayerApp.DAL.EF;
using NLayerApp.DAL.Interfaces;
using System.Data.Entity;

namespace NLayerApp.DAL.Repositories
{
    public class PhoneRepository : IRepository<Phone>
    {
        private MobileContext db;

        public PhoneRepository(MobileContext context)
        {
            this.db = context;
        }

        public IEnumerable<Phone> GetAll()
        {
            return db.Phones;
        }

        public Phone Get(int id)
        {
            return db.Phones.Find(id);
        }

        public void Create(Phone book)
        {
            db.Phones.Add(book);
        }

        public void Update(Phone book)
        {
            db.Entry(book).State = EntityState.Modified;
        }

        public IEnumerable<Phone> Find(Func<Phone, Boolean> predicate)
        {
            return db.Phones.Where(predicate).ToList();
        }

        public void Delete(int id)
        {
            Phone book = db.Phones.Find(id);
            if (book != null)
                db.Phones.Remove(book);
        }
    }
}

Также добавим в эту же папку класс репозитория для заказов OrderRepository:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using NLayerApp.DAL.Entities;
using NLayerApp.DAL.EF;
using NLayerApp.DAL.Interfaces;

namespace NLayerApp.DAL.Repositories
{
    public class OrderRepository : IRepository<Order>
    {
        private MobileContext db;

        public OrderRepository(MobileContext context)
        {
            this.db = context;
        }

        public IEnumerable<Order> GetAll()
        {
            return db.Orders.Include(o => o.Phone);
        }

        public Order Get(int id)
        {
            return db.Orders.Find(id);
        }

        public void Create(Order order)
        {
            db.Orders.Add(order);
        }

        public void Update(Order order)
        {
            db.Entry(order).State = EntityState.Modified;
        }
        public IEnumerable<Order> Find(Func<Order, Boolean> predicate)
        {
            return db.Orders.Include(o => o.Phone).Where(predicate).ToList();
        }
        public void Delete(int id)
        {
            Order order = db.Orders.Find(id);
            if (order != null)
                db.Orders.Remove(order);
        }
    }
}

И также в папку Repositories добавим класс EFUnitOfWork:

using System;
using NLayerApp.DAL.EF;
using NLayerApp.DAL.Interfaces;
using NLayerApp.DAL.Entities;

namespace NLayerApp.DAL.Repositories
{
    public class EFUnitOfWork : IUnitOfWork
    {
        private MobileContext db;
        private PhoneRepository phoneRepository;
        private OrderRepository orderRepository;

        public EFUnitOfWork(string connectionString)
        {
            db = new MobileContext(connectionString);
        }
        public IRepository<Phone> Phones
        {
            get
            {
                if (phoneRepository == null)
                    phoneRepository = new PhoneRepository(db);
                return phoneRepository;
            } 
        }

        public IRepository<Order> Orders
        {
            get
            {
                if (orderRepository == null)
                    orderRepository = new OrderRepository(db);
                return orderRepository;
            }
        }

        public void Save()
        {
            db.SaveChanges();
        }

        private bool disposed = false;

        public virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    db.Dispose();
                }
				this.disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

Класс EFUnitOfWork в конструкторе принимает строку - названия подключения, которая потом будет передаваться в конструктор контекста данных. Собственно через EFUnitOfWork мы и будем взаимодействовать с базой данных.

В итоге структура проекта будет выглядеть следующим образом:

Data Access Layer in ASP.NET MVC

Собственно, и весь уровень доступа к данным, который мы могли бы сделать для проекта из прошлой темы, и теперь перейдем к построению бизнес-логики.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850