Recently, I was writing the infrastructure part of My Movie Review SPA app using ASP.NET Core version. Then, I landed in a really weird situation where in DBSet.Find() a piece is missing. This is a really crucial extension method for finding the record based on the primary key. In order to find the solution, I thought it would be nice to talk to EF Guru Julie Lerman directly. Here is what I asked her and what she replied on the same.
Here, at this point I got the confirmation, this feature is yet to be included by EF Team. Hence, I decided to use the interim solution provided by the EF Team themselves. Below is the extension method which I have written to serve the same result.
- using System;
- using System.Linq;
- using System.Linq.Expressions;
- using Microsoft.Data.Entity;
- using Microsoft.Data.Entity.Infrastructure;
-
- namespace MovieReviewSPA.Data.Helpers
- {
- public static class Extensions
- {
- public static TEntity Find<TEntity>(this DbSet<TEntity> set, params object[] keyValues) where TEntity : class
- {
- var context = ((IInfrastructure<IServiceProvider>)set).GetService<DbContext>();
-
- var entityType = context.Model.FindEntityType(typeof(TEntity));
- var key = entityType.FindPrimaryKey();
-
- var entries = context.ChangeTracker.Entries<TEntity>();
-
- var i = 0;
- foreach (var property in key.Properties)
- {
- entries = Enumerable.Where(entries, e => e.Property(property.Name).CurrentValue == keyValues[i]);
- i++;
- }
-
- var entry = entries.FirstOrDefault();
- if (entry != null)
- {
-
- return entry.Entity;
- }
-
-
-
- var parameter = Expression.Parameter(typeof(TEntity), "x");
- var query = Queryable.Where(set, (Expression<Func<TEntity, bool>>)
- Expression.Lambda(
- Expression.Equal(
- Expression.Property(parameter, "Id"),
- Expression.Constant(keyValues[0])),
- parameter));
-
-
- return query.FirstOrDefault();
- }
- }
- }
And, here is the completed Repository Pattern for my project.
- using System;
- using System.Linq;
- using Microsoft.Data.Entity;
- using Microsoft.Data.Entity.ChangeTracking;
- using MovieReviewSPA.Data.Contracts;
- using MovieReviewSPA.Data.Helpers;
- using DbContext = Microsoft.Data.Entity.DbContext;
- using EntityState = Microsoft.Data.Entity.EntityState;
-
- namespace MovieReviewSPA.Data
- {
- public class EFRepository<T> : IRepository<T> where T : class
- {
- public EFRepository(DbContext dbContext)
- {
- if (dbContext == null)
- throw new ArgumentNullException("dbContext");
- DbContext = dbContext;
- DbSet = DbContext.Set<T>();
- }
-
- protected DbContext DbContext { get; set; }
- protected DbSet<T> DbSet { get; set; }
- public virtual IQueryable<T> GetAll()
- {
- return DbSet;
- }
-
- public virtual T GetById(int id)
- {
-
-
-
- return DbSet.Find(id);
- }
-
- public virtual void Add(T entity)
- {
- EntityEntry<T> dbEntityEntry = DbContext.Entry(entity);
- if (dbEntityEntry.State != (EntityState) EntityState.Detached)
- {
- dbEntityEntry.State = EntityState.Added;
- }
- else
- {
- DbSet.Add(entity);
- }
- }
-
- public virtual void Update(T entity)
- {
- EntityEntry<T> dbEntityEntry = DbContext.Entry(entity);
- if (dbEntityEntry.State != (EntityState) EntityState.Detached)
- {
- DbSet.Attach(entity);
- }
- dbEntityEntry.State = EntityState.Modified;
- }
-
- public void Delete(T entity)
- {
- EntityEntry<T> dbEntityEntry = DbContext.Entry(entity);
- if (dbEntityEntry.State != (EntityState) EntityState.Deleted)
- {
- dbEntityEntry.State = EntityState.Deleted;
- }
- else
- {
- DbSet.Attach(entity);
- DbSet.Remove(entity);
- }
- }
-
- public void Delete(int id)
- {
- var entity = GetById(id);
- if (entity == null) return;
-
- Delete(entity);
- }
- }
-
- }
Now, below is the glimpse of the solution structure so far for my Movie Review SPA coming up using ASP.NET Core, WEB-API, Angular JS, Entity Framework and tons of new things.
I hope you have liked this discussion. Thanks for joining me.
Join the conversation! Your thoughts help the community grow.