Entity Framework (EF) Core is a lightweight, extensible, and cross-platform version of the popular Entity Framework data access technology.
EF Core is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write. Object-relational mapping is a technique that enables developers to work with data in object-oriented way by performing the work required to map between objects defined in an application’s programming language and data stored in relational database.
You can download the source code from here.
Prerequisites
- Visual Studio 2017
- .Net Core Framework 2.0
Setup projects in Visual Studio
- Create a new solution in Visual Studio. Here I created a solution HiveStore.
- Add a new .Net Core library project for Entity or model classes to the solution. Here I created a library project HiveStore.Entity.
- Add a new .Net Core library project for data access related classes to the solution. In demo application HiveStore.DataAccess refers to this.
- Add a new .Net Core console application to write the test code.
- Below are the projects in the solutions
- HiveStore.TestConsole.
- HiveStore.Entity
- HiveStore.DataAccess
Setup Hive.Entity project
- Add a BaseEntity class to Codify.Entity project. The BaseEntity contains common properties like CreatedDate, CreatedBy etc. which are part of all tables.
1 2 3 4 5 6 7 8 9 |
public abstract class BaseEntity { public DateTime CreatedDate { get; set; } public string CreatedBy { get; set; } public DateTime ModifiedDate { get; set; } public string ModifiedBy { get; set; } public bool IsDeleted { get; set; } public virtual byte[] RecordTimeStamp { get; set; } } |
- Add a class file for Employee entity.
1234567891011public class EmployeeEntity : BaseEntity{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public string Address { get; set; }public string City { get; set; }public string Country { get; set; }public virtual ICollection<OrderEntity> OrderEntities { get; set; }} - Add a class file for Product entity
1 2 3 4 5 6 7 8 |
public class ProductEntity : BaseEntity { public int Id { get; set; } public string ProductName { get; set; } public decimal UnitPrice { get; set; } public ICollection<OrderDetailsEntity> OrderDetails { get; set; } } |
- Add a class file for Order entity
1 2 3 4 5 6 7 8 |
public class OrderEntity : BaseEntity { public int Id { get; set; } public int EmployeeId { get; set; } public DateTime RequiredDate { get; set; } public string ShipAddress { get; set; } public virtual EmployeeEntity Employee { get; set; } } |
- Add a class file for Order Details Entity.
1 2 3 4 5 6 7 8 9 10 11 |
public class OrderDetailsEntity : BaseEntity { public int Id { get; set; } public int OrderId { get; set; } public int ProductId { get; set; } public Decimal UnitPrice { get; set; } public int Quantity { get; set; } public Decimal Discount { get; set; } public virtual OrderEntity Order { get; set; } public virtual ProductEntity Product { get; set; } } |
Setup Hive.DataAccess project
- Now lets create Repository classes and DataContext class. For this we need to install EntityFramework package using nuget.
Open Package Manager Console from Tools -> Nuget Package Manager and issue below command in console.
1 |
Install-Package Microsoft.EntityFrameworkCore.SqlServer |
- Create an abstract BaseRepository class at the project root. This base class is inherited by all repository classes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public abstract class BaseRepository { private readonly DbContext _dataContext; protected BaseRepository(DbContext dataContext) { _dataContext = dataContext; } public string SaveChanges() { var errMsg = string.Empty; try { var result = _dataContext.SaveChanges(); if (result > 0) { return "Success"; } } catch (DbUpdateException dbUpdateExceptionEx) { var err = dbUpdateExceptionEx.InnerException.InnerException.Message; errMsg = err.Replace("\r\n", "").Replace("The statement has been terminated.", ""); } return errMsg; } } |
- Create an abstract BasicEntityConfiguration class in the project root. This contains column level constraints for properties in BaseEntity.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public abstract class BasicEntityConfiguration { public void ConfigureBase<TEntity>(EntityTypeBuilder<TEntity> builder) where TEntity : BaseEntity { builder.Property(p => p.CreatedDate).HasColumnName("CREATED_DATE").IsRequired(); builder.Property(p => p.CreatedBy).HasColumnName("CREATED_BY").HasMaxLength(50).IsRequired(); builder.Property(p => p.ModifiedDate).HasColumnName("MODIFIED_DATE").IsRequired(); builder.Property(p => p.ModifiedBy).HasColumnName("MODIFIED_BY").HasMaxLength(50).IsRequired(); builder.Property(p => p.IsDeleted).HasColumnName("IS_DELETED").IsRequired(); builder.Property(e => e.RecordTimeStamp).HasColumnName("RTS").IsRowVersion().IsRequired(); } } |
- Add EmployeeConfiguration class to Employee -> Configuration folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class EmployeeConfiguration<TEntity> : BasicEntityConfiguration, IEntityTypeConfiguration<EmployeeEntity> { public void Configure(EntityTypeBuilder<EmployeeEntity> builder) { builder.ToTable("Employee", "hive"); builder.Property(p => p.Id).HasColumnName("EMPLOYEE_ID"); builder.Property(p => p.FirstName).HasColumnName("FIRST_NAME").HasMaxLength(200).IsRequired(); builder.Property(p => p.LastName).HasColumnName("LAST_NAME").HasMaxLength(200).IsRequired(); builder.Property(p => p.Address).HasColumnName("ADDRESS").HasMaxLength(200); builder.Property(p => p.City).HasColumnName("CITY").HasMaxLength(200); builder.Property(p => p.Country).HasColumnName("COUNTRY").HasMaxLength(200); ConfigureBase(builder); } } |
- Add OrderConfiguration class in Order-> Configuration folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class OrderConfiguration<TEntity> : BasicEntityConfiguration, IEntityTypeConfiguration<OrderEntity> { public void Configure(EntityTypeBuilder<OrderEntity> builder) { builder.ToTable("Order", "hive"); builder.Property(p => p.Id).HasColumnName("ORDER_ID"); builder.Property(p => p.EmployeeId).HasColumnName("EMPLOYEE_ID"); builder.Property(p => p.RequiredDate).HasColumnName("REQUIRED_DATE"); builder.Property(p => p.ShipAddress).HasColumnName("SHIP_ADDRESS"); ConfigureBase(builder); } } |
- Add ProductConfiguration class in Product-> Configuration folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class ProductConfiguration<TEntity> : BasicEntityConfiguration, IEntityTypeConfiguration<ProductEntity> { public void Configure(EntityTypeBuilder<ProductEntity> builder) { builder.ToTable("Product", "hive"); builder.Property(p => p.Id).HasColumnName("PRODUCT_ID"); builder.Property(p => p.ProductName).HasColumnName("PRODUCT_NAME").HasMaxLength(200).IsRequired(); builder.Property(p => p.UnitPrice).HasColumnName("UNIT_PRICE"); ConfigureBase(builder); } } |
- Add OrderDetailsConfiguration in Order -> Configuration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class OrderDetailsConfiguration<TEntity> : BasicEntityConfiguration, IEntityTypeConfiguration<OrderDetailsEntity> { public void Configure(EntityTypeBuilder<OrderDetailsEntity> builder) { builder.ToTable("OrderDetails", "hive"); builder.Property(p => p.Id).HasColumnName("ORDER_DETAILS_ID"); builder.Property(p => p.OrderId).HasColumnName("ORDER_ID"); builder.Property(p => p.ProductId).HasColumnName("PRODUCT_ID"); builder.Property(p => p.UnitPrice).HasColumnName("UNIT_PRICE"); builder.Property(p => p.Quantity).HasColumnName("QUANTITY"); builder.Property(p => p.Discount).HasColumnName("DISCOUNT"); ConfigureBase(builder); } } |
- Create IEmployeeRepository in Employee-> Repository -> Interface folder.
- Create IOrderRepository, IOrderDetailsRepository in Order -> Repository -> Interface folder.
- Create IProductRepository in Product -> Repository -> Interface folder.
1 2 3 4 5 6 7 |
public interface IEmployeeRepository { void AddEmployee(EmployeeEntity employeeEntity); List<EmployeeEntity> GetAllEmployees(); EmployeeEntity GetEmployeeById(int employeeId); string SaveChanges(); } |
1 2 3 4 5 6 |
public interface IProductRepository { void AddProduct(ProductEntity productEntity); List<ProductEntity> GetAllProducts(); string SaveChanges(); } |
- Create EmployeeRepository in Employee-> Repository folder.
- Create OrderRepository, OrderDetailsRepository in Order -> Repository folder.
- Create ProductRepository in Product -> Repository folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public class EmployeeRepository : BaseRepository, IEmployeeRepository { private readonly DbContext _dataContext; public EmployeeRepository(DbContext dataContext) : base(dataContext) { _dataContext = dataContext; } public void AddEmployee(EmployeeEntity employeeEntity) { if (employeeEntity == null) { throw new ArgumentNullException("employeeEntity"); } var set = _dataContext.Set<EmployeeEntity>(); set.Add(employeeEntity); } public List<EmployeeEntity> GetAllEmployees() { return _dataContext.Set<EmployeeEntity>().Where(x => !x.IsDeleted).ToList(); } public EmployeeEntity GetEmployeeById(int employeeId) { return _dataContext.Set<EmployeeEntity>().FirstOrDefault(x => x.Id.Equals(employeeId)); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class ProductRepository : BaseRepository, IProductRepository { private readonly DbContext _dataContext; public ProductRepository(DbContext dataContext) : base(dataContext) { _dataContext = dataContext; } public void AddProduct(ProductEntity productEntity) { if (productEntity == null) { throw new ArgumentNullException("employeeEntity"); } var set = _dataContext.Set<ProductEntity>(); set.Add(productEntity); } public List<ProductEntity> GetAllProducts() { return _dataContext.Set<ProductEntity>().Where(x => !x.IsDeleted).ToList(); } } |
- And finally lets create the DataContext class. Add a class file for HiveDataContext.cs in Hive.DataAccess project and add below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class HiveDataContext : DbContext { public DbSet<EmployeeEntity> Employees { get; set; } public DbSet<ProductEntity> Products { get; set; } public DbSet<OrderEntity> Orders { get; set; } public DbSet<OrderDetailsEntity> OrderDetails { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server=DESKTOP-PSN38VA\SQLEXPRESS;Database=Hive;Trusted_Connection=True"); } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // Customizations must go after base.OnModelCreating(builder) builder.ApplyConfiguration(new EmployeeConfiguration<EmployeeEntity>()); builder.ApplyConfiguration(new ProductConfiguration<ProductEntity>()); builder.ApplyConfiguration(new OrderConfiguration<OrderEntity>()); builder.ApplyConfiguration(new OrderDetailsConfiguration<OrderDetailsEntity>()); // Imagine a ton more customizations } } |
- Change the connection string to point to your database in below method.
1 2 3 4 |
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server=DESKTOP-PSN38VA\SQLEXPRESS;Database=Hive;Trusted_Connection=True"); } |
Creating and Managing Database Schemas
Migrations
Migrations provide a way to incrementally apply schema changes to the database to keep it in sync with your EF Core model while preserving existing data in the database.
Creating the Database
So we have created our model classes. Now lets create the database. To do this, add an initial migration. For this we need to Install the EF Core Tools using Package Manager console. Select HiveStore.DataAccess as the default project.
1 |
Install-Package Microsoft.EntityFrameworkCore.Tools |
Run below command in Package Manager Console to create Migrations folder.
1 |
Add-Migration InitialCreate |
If this command does not generate Migration file add below setting in HiveStore.DataAccess.csproj file.
1 2 3 |
<PropertyGroup> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> </PropertyGroup> |
Run below command to create Database and tables.
1 |
Update-Database |
DB Diagram
Setup Hive.TestConsole Project
- Install Microsoft.EntityFrameworkCore.SqlServer Package using PMC.
- Add below code in Program.cs file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
class Program { static void Main(string[] args) { InsertEmployees(); Console.ReadKey(); } private static void InsertEmployees() { CreateEmployee("Joy", "Smith", "Los Angeles", "USA"); CreateEmployee("Abram", "Ivanov", "Moscow", "Russia"); CreateEmployee("Aryan", "Sodhi", "Delhi", "India"); CreateEmployee("James", "Williams", "Sidney", "Australia"); CreateEmployee("Muhammed", "Emir", "Istanbul", "Turkey"); } private static void CreateEmployee(string firstName, string lastName, string city, string country) { EmployeeEntity employee = new EmployeeEntity(); employee.City = city; employee.Country = country; employee.FirstName = firstName; employee.LastName = lastName; employee.CreatedBy = System.Environment.UserName; employee.ModifiedBy = System.Environment.UserName; employee.CreatedDate = DateTime.Now; employee.ModifiedDate = DateTime.Now; using (HiveDataContext hsDataContext = new HiveDataContext()) { IEmployeeRepository empRepository = new EmployeeRepository(hsDataContext); empRepository.AddEmployee(employee); string message = empRepository.SaveChanges(); Console.WriteLine(message); } } } |
- Execute the program and after successful run records are inserted in to [hive].[Employee] table.
You can download the source code from here.
One comment on “Entity Framework Core 2.0 Repository Pattern”