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.
  1. using System;
  2. using System.Linq;
  3. using System.Linq.Expressions;
  4. using Microsoft.Data.Entity;
  5. using Microsoft.Data.Entity.Infrastructure;
  6. namespace MovieReviewSPA.Data.Helpers
  7. {
  8. public static class Extensions
  9. {
  10. public static TEntity Find<TEntity>(this DbSet<TEntity> set, params object[] keyValues) where TEntity : class
  11. {
  12. var context = ((IInfrastructure<IServiceProvider>)set).GetService<DbContext>();
  13. var entityType = context.Model.FindEntityType(typeof(TEntity));
  14. var key = entityType.FindPrimaryKey();
  15. var entries = context.ChangeTracker.Entries<TEntity>();
  16. var i = 0;
  17. foreach (var property in key.Properties)
  18. {
  19. entries = Enumerable.Where(entries, e => e.Property(property.Name).CurrentValue == keyValues[i]);
  20. i++;
  21. }
  22. var entry = entries.FirstOrDefault();
  23. if (entry != null)
  24. {
  25. // Return the local object if it exists.
  26. return entry.Entity;
  27. }
  28. // TODO: Build the real LINQ Expression
  29. // set.Where(x => x.Id == keyValues[0]);
  30. var parameter = Expression.Parameter(typeof(TEntity), "x");
  31. var query = Queryable.Where(set, (Expression<Func<TEntity, bool>>)
  32. Expression.Lambda(
  33. Expression.Equal(
  34. Expression.Property(parameter, "Id"),
  35. Expression.Constant(keyValues[0])),
  36. parameter));
  37. // Look in the database
  38. return query.FirstOrDefault();
  39. }
  40. }
  41. }
And, here is the completed Repository Pattern for my project.
  1. using System;
  2. using System.Linq;
  3. using Microsoft.Data.Entity;
  4. using Microsoft.Data.Entity.ChangeTracking;
  5. using MovieReviewSPA.Data.Contracts;
  6. using MovieReviewSPA.Data.Helpers;
  7. using DbContext = Microsoft.Data.Entity.DbContext;
  8. using EntityState = Microsoft.Data.Entity.EntityState;
  9. namespace MovieReviewSPA.Data
  10. {
  11. public class EFRepository<T> : IRepository<T> where T : class
  12. {
  13. public EFRepository(DbContext dbContext)
  14. {
  15. if (dbContext == null)
  16. throw new ArgumentNullException("dbContext");
  17. DbContext = dbContext;
  18. DbSet = DbContext.Set<T>();
  19. }
  20. protected DbContext DbContext { get; set; }
  21. protected DbSet<T> DbSet { get; set; }
  22. public virtual IQueryable<T> GetAll()
  23. {
  24. return DbSet;
  25. }
  26. public virtual T GetById(int id)
  27. {
  28. //EF Core Will be updated shortly with Find Extension by Default
  29. //Here, I have written Extension method for the same
  30. //Source:- http://stackoverflow.com/questions/29030472/dbset-doesnt-have-a-find-method-in-ef7/29082410#29082410
  31. return DbSet.Find(id);
  32. }
  33. public virtual void Add(T entity)
  34. {
  35. EntityEntry<T> dbEntityEntry = DbContext.Entry(entity);
  36. if (dbEntityEntry.State != (EntityState) EntityState.Detached)
  37. {
  38. dbEntityEntry.State = EntityState.Added;
  39. }
  40. else
  41. {
  42. DbSet.Add(entity);
  43. }
  44. }
  45. public virtual void Update(T entity)
  46. {
  47. EntityEntry<T> dbEntityEntry = DbContext.Entry(entity);
  48. if (dbEntityEntry.State != (EntityState) EntityState.Detached)
  49. {
  50. DbSet.Attach(entity);
  51. }
  52. dbEntityEntry.State = EntityState.Modified;
  53. }
  54. public void Delete(T entity)
  55. {
  56. EntityEntry<T> dbEntityEntry = DbContext.Entry(entity);
  57. if (dbEntityEntry.State != (EntityState) EntityState.Deleted)
  58. {
  59. dbEntityEntry.State = EntityState.Deleted;
  60. }
  61. else
  62. {
  63. DbSet.Attach(entity);
  64. DbSet.Remove(entity);
  65. }
  66. }
  67. public void Delete(int id)
  68. {
  69. var entity = GetById(id);
  70. if (entity == null) return;
  71. Delete(entity);
  72. }
  73. }
  74. }
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.