Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ packages
bin
obj
TestResults
.nuget

#include package target files which may be required for msbuild
!packages/*.targets
Expand Down
226 changes: 226 additions & 0 deletions EntityFrameworkCoreRepository/BaseRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
using EntityFramework.Repository.Core.Interfaces;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace EntityFramework.Repository.Core
{
public abstract class BaseRepository<C, T> :
IBaseRepository<C, T>
, IDisposable
where T : class
where C : DbContext
{
protected C Context { get; set; }
protected Lazy<List<string>> IgnoreFieldsOnUpdate = new Lazy<List<string>>();
protected Lazy<List<Expression<Func<T, bool>>>> IgnoreFieldsOnUpdate2 = new Lazy<List<Expression<Func<T, bool>>>>();

protected BaseRepository(C context)
{
Context = context;
}

public virtual void AddUpdateIgnoreField(string fieldName)
{
IgnoreFieldsOnUpdate.Value.Add(fieldName);
}

public virtual void AddUpdateIgnoreField(Expression<Func<T, bool>> fieldName)
{
IgnoreFieldsOnUpdate2.Value.Add(fieldName);
}

public virtual T? Find(int id)
{
return Context.Set<T>().Find(id);
}

public virtual T? Find(params object[] ids)
{
return Context.Set<T>().Find(ids);
}

public virtual async Task<T?> FindAsync(int id)
{
return await Context.Set<T>().FindAsync(id);
}

public virtual async Task<T?> FindAsync(params object[] ids)
{
return await Context.Set<T>().FindAsync(ids);
}

public virtual IQueryable<T> FindBy(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate);
}

public virtual bool Exists(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().AsNoTracking().Any(predicate);
}

public virtual void Delete(T entity)
{
Context.Set<T>().Remove(entity);
}

public virtual void Delete(IEnumerable<T> entities)
{
foreach (T entity in entities)
{
Delete(entity);
}
}

public virtual void Reload(T entity)
{
Context.Entry<T>(entity).Reload();
}

public async virtual Task ReloadAsync(T entity)
{
await Context.Entry<T>(entity).ReloadAsync();
}

public virtual IQueryable<T> FindByReadOnly(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().AsNoTracking().Where(predicate);
}

public virtual IQueryable<T> GetAll()
{
return Context.Set<T>().AsNoTracking();
}

public virtual T Add(T entity)
{
Context.Set<T>().Add(entity);
return entity;
}

public virtual IEnumerable<T> Add(IEnumerable<T> entities)
{
Context.Set<T>().AddRange(entities);
return entities;
}

public virtual void Update(T entity, int id)
{
var entityToUpdate = Context.Set<T>().Find(id);

if (entityToUpdate == null) throw CreateEntityNotFoundException<ArgumentOutOfRangeException>(id.ToString(), typeof(T).Name);

Context.Entry(entityToUpdate).CurrentValues.SetValues(entity);

MarkIgnoreFields(entityToUpdate);
}

public virtual void Update(T entity, Expression<Func<T, bool>> predicate)
{
var entityToUpdate = Context.Set<T>().Where(predicate).SingleOrDefault();

if (entityToUpdate == null) throw CreateEntityNotFoundException<ArgumentOutOfRangeException>(predicate.ToString(), typeof(T).Name);

Context.Entry(entityToUpdate).CurrentValues.SetValues(entity);

MarkIgnoreFields(entityToUpdate);
}

public virtual void Update(Delta<T> delta, params object[] ids)
{
var entityToUpdate = Context.Set<T>().Find(ids);

if (entityToUpdate == null) throw CreateEntityNotFoundException<ArgumentOutOfRangeException>(ids.ToString()!, typeof(T).Name);

foreach (string field in delta.UpdatedFields())
{
var fieldToSet = typeof(T).GetProperty(field);
var dataOrigin = delta.Internal.GetType().GetProperty(field);

fieldToSet!.SetValue(entityToUpdate, dataOrigin!.GetValue(delta.Internal));
}

MarkIgnoreFields(entityToUpdate);
}

public void Update(Delta<T> delta, Expression<Func<T, bool>> predicate)
{
var entityToUpdate = Context.Set<T>().Where(predicate).SingleOrDefault();

if (entityToUpdate == null) throw CreateEntityNotFoundException<ArgumentOutOfRangeException>(predicate.ToString(), typeof(T).Name);

foreach (string field in delta.UpdatedFields())
{
var fieldToSet = typeof(T).GetProperty(field);
var dataOrigin = delta.Internal.GetType().GetProperty(field);

fieldToSet!.SetValue(entityToUpdate, dataOrigin!.GetValue(delta.Internal));
}

MarkIgnoreFields(entityToUpdate);
}

protected virtual E CreateEntityNotFoundException<E>(string entityId, string entityType)
{
return (E)Activator.CreateInstance(typeof(E), string.Format("{0} is not a valid identity key(s) for {1}.", entityId, entityType))!;
}

protected virtual void MarkIgnoreFields(T entityToUpdate)
{
if (IgnoreFieldsOnUpdate.IsValueCreated)
{ IgnoreFieldsOnUpdate.Value.ForEach(ignoreField => Context.Entry(entityToUpdate).Property(ignoreField).IsModified = false); }

if (IgnoreFieldsOnUpdate2.IsValueCreated)
{ IgnoreFieldsOnUpdate2.Value.ForEach(ignoreField => Context.Entry(entityToUpdate).Property(ignoreField).IsModified = false); }
}

public async virtual Task<int> SaveAsync()
{
return await Context.SaveChangesAsync();
}

public virtual int Save()
{
return Context.SaveChanges();
}

public virtual int Count()
{
return Context.Set<T>().Count();
}

public async virtual Task<int> CountAsync()
{
return await Context.Set<T>().CountAsync();
}

#region IDisposable Support
private bool disposedValue = false;

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
if (Context != null)
{
Context.Dispose();
}
}

disposedValue = true;
}
}

public void Dispose()
{
Dispose(true);
}
#endregion
}
}
26 changes: 26 additions & 0 deletions EntityFrameworkCoreRepository/DatabaseFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Microsoft.EntityFrameworkCore;

namespace EntityFramework.Repository.Core
{
public interface IDatabaseFactory<C>
{
C GetNewDbContext();
}

public class DatabaseFactory<C> : IDatabaseFactory<C>
where C : DbContext
{
protected string DbConnectionString { get; set; }

public DatabaseFactory(string connectionString)
{
DbConnectionString = connectionString;
}

public virtual C GetNewDbContext()
{
return (C)Activator.CreateInstance(typeof(C), DbConnectionString)!;
}
}
}
40 changes: 40 additions & 0 deletions EntityFrameworkCoreRepository/Delta.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;

namespace EntityFramework.Repository.Core
{
public class Delta<T> where T : class
{
List<string> Fields { get; set; }
public T Internal { get; set; }

public List<string> UpdatedFields()
{
return Fields;
}

public Delta()
{
Internal = (T)Activator.CreateInstance(typeof(T))!;
Fields = new List<string>();
}

public void SetValue(string fieldName, object data)
{
var prop1 = typeof(T).GetProperty(fieldName);
if (prop1 == null)
{
throw new ArgumentException($"{fieldName} was not a property found on the object.");
}
try
{
prop1.SetValue(Internal, data);
Fields.Add(fieldName);
}
catch (ArgumentException)
{
throw;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>EntityFramework.Repository.Core</RootNamespace>
<AssemblyName>EntityFramework.Repository.Core</AssemblyName>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
</ItemGroup>

</Project>
24 changes: 24 additions & 0 deletions EntityFrameworkCoreRepository/Interfaces/IBaseRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace EntityFramework.Repository.Core.Interfaces
{
public interface IBaseRepository<C, T> :
IDisposable
, IReadFunctions<T>
, IUpdateFunctions<T>
, IDeleteFunctions<T>
, ICreateFunctions<T>
, ISaveFunctions<T>
where T : class
where C : DbContext
{
int Count();
Task<int> CountAsync();
bool Exists(Expression<Func<T, bool>> predicate);
void Reload(T entity);
Task ReloadAsync(T entity);
}
}
11 changes: 11 additions & 0 deletions EntityFrameworkCoreRepository/Interfaces/ICreateFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace EntityFramework.Repository.Core.Interfaces
{
public interface ICreateFunctions<T>
where T : class
{
T Add(T entity);
IEnumerable<T> Add(IEnumerable<T> entities);
}
}
11 changes: 11 additions & 0 deletions EntityFrameworkCoreRepository/Interfaces/IDeleteFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace EntityFramework.Repository.Core.Interfaces
{
public interface IDeleteFunctions<T>
where T : class
{
void Delete(T entity);
void Delete(IEnumerable<T> entities);
}
}
19 changes: 19 additions & 0 deletions EntityFrameworkCoreRepository/Interfaces/IReadFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace EntityFramework.Repository.Core.Interfaces
{
public interface IReadFunctions<T>
where T : class
{
IQueryable<T> GetAll();
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
IQueryable<T> FindByReadOnly(Expression<Func<T, bool>> predicate);
T? Find(int id);
T? Find(params object[] ids);
Task<T?> FindAsync(int id);
Task<T?> FindAsync(params object[] ids);
}
}
11 changes: 11 additions & 0 deletions EntityFrameworkCoreRepository/Interfaces/ISaveFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Threading.Tasks;

namespace EntityFramework.Repository.Core.Interfaces
{
public interface ISaveFunctions<T>
where T : class
{
Task<int> SaveAsync();
int Save();
}
}
Loading