AuxiliaryLibraries.GenericRepository.Core
1.0.4
See the version list below for details.
dotnet add package AuxiliaryLibraries.GenericRepository.Core --version 1.0.4
NuGet\Install-Package AuxiliaryLibraries.GenericRepository.Core -Version 1.0.4
<PackageReference Include="AuxiliaryLibraries.GenericRepository.Core" Version="1.0.4" />
paket add AuxiliaryLibraries.GenericRepository.Core --version 1.0.4
#r "nuget: AuxiliaryLibraries.GenericRepository.Core, 1.0.4"
// Install AuxiliaryLibraries.GenericRepository.Core as a Cake Addin #addin nuget:?package=AuxiliaryLibraries.GenericRepository.Core&version=1.0.4 // Install AuxiliaryLibraries.GenericRepository.Core as a Cake Tool #tool nuget:?package=AuxiliaryLibraries.GenericRepository.Core&version=1.0.4
There might be no project that doesn't need this library. With the help of this library you are able to get rid of implementing CRUD operations for all of you entities. You should just configure a few lines for every enity and that's it, you have implemented all of CRUD operations along with lots of other useful functions.
Besides, as this library use AuxiliaryLibraries.CacheManager, if you configure CacheManager, you will access a very handy feature which is caching with no extra effort.
This use generic repository and unit of work design patterns for implementing all of its functions. Furthermore, CacheManager uses Redis.
Table of Contents
- About The Library
- How it works
- How to use
- What do you have now
- Easy Peasy caching
- Configuration
About The Library
This library helps you to implement your projects faster than usual, because you can focus on implementing logic of your project and leave the Data Access Layer to this library. You have to do a few steps as described below. Entity Framework Core is used in this library and if you choose another types of ORM this library might not useful for you.
How it works
There are a few base classes inside the library, you should create one interface and one repository class for each entity, and inherit them from those base classes. If you need to change the functionality of any of default functions, you can simply override them. Or you can add any other functionality to your repositories. After that you must register your classes to your IOC container.
How to use
Let's imagine we have one entity. In real projects you will have more than that. Do these steps for all of them.
Table - Entity
public partial class Person
{
public long Id { get; set; }
public string FirstName { get; set; }
public string LastnametName { get; set; }
public string Address { get; set; }
public DateTime CreateDate { get; set; }
public DateTime LastModifiedDate { get; set; }
}
Repository
Now you should create one interface and one Repository class as follows:
Person Repository Interface
There is a base interface called IRepository. Create an interface and inherit it from IRepository<TEntity>:
public interface IPersonRepository : IRepository<Person>
{
// For default you do not need to add anything here.
}
Person Repository
There is a base interface called Repository. Create a class and inherit it from Repository<TEntity> and IPersonRepository: If you want to use Cashing follow code below:
public class PersonRepository : Repository<Person>, IPersonRepository
{
// TestDbContext is the name of your DbContext, Replace it with your own DbContext name
private TestDbContext TestDbContext => Context as TestDbContext;
public PersonRepository(TestDbContext context, ICacheService cacheService) : base(context, cacheService)
{
// For default you do not need to add anything here.
}
}
But if you don't want to use Cashing there is no need to pass ICacheService. In this case, wherevere we have setCache, setCache won't work. Besides, wherevere we have RefreshCache, TryGet, TryGetCache, or anything else related to cache won't work.
public class PersonRepository : Repository<Person>, IPersonRepository
{
// TestDbContext is the name of your DbContext, Replace it with your own DbContext name
private TestDbContext TestDbContext => Context as TestDbContext;
public PersonRepository(TestDbContext context) : base(context)
{
// For default you do not need to add anything here.
}
}
If you need to add any other functionality to your repositories you can do like this:
Person Repository Interface
public interface IPersonRepository : IRepository<Person>
{
Task<Person> GetLastSourceAsync(bool setCache = false);
}
Person Repository
public class PersonRepository : Repository<Person>, IPersonRepository
{
// TestDbContext is the name of your DbContext, Replace it with your own DbContext name
private TestDbContext TestDbContext => Context as TestDbContext;
// Or
// public PersonRepository(TestDbContext context) : base(context)
public PersonRepository(TestDbContext context, ICacheService cacheService) : base(context, cacheService)
{
public virtual async Task<Person> GetLastSourceAsync(bool setCache = false)
{
var cacheKey = CacheConventions.Cachekey<Person>(id: 1, baseKey: "Last");
if (!CacheService.TryGet(cacheKey, out Person cachedItem))
{
cachedItem = await TestDbContext.People.OrderByDescending(x => x.CreateDate).FirstOrDefaultAsync(x => !string.IsNullOrEmpty(x.FirstName));
if (setCache && cachedItem != null)
CacheService.Set(cacheKey, cachedItem);
}
return cachedItem;
}
}
}
UnitOfWork
Now it's time to have UnitOfWork. Create an interface and a class for UnitOfWork
IUnitOfWork
There is a base interface called IUnitOfWork. Create an interface and inherit it from that IUnitOfWork. Then you have to add all of your repositories here inside this interface just like below:
public interface ITestUnitOfWork : IUnitOfWork
{
IPersonRepository People { get; }
}
UnitOfWork
There is a base class called UnitOfWork. Create a class and inherit it from that UnitOfWork and ITestUnitOfWork. Then you have to decorate your class as follows and add all of your repositories here inside this class just like below:
public class TestUnitOfWork : UnitOfWork, ITestUnitOfWork
{
private TestDbContext TestDbContext => Context as TestDbContext;
public TestUnitOfWork
(
TestDbContext context,
ICacheService cacheService, // This is optional, you are able to not pass it.
IPersonRepository PersonRepository
) : base(context, cacheService)
{
People = PersonRepository;
}
public IPersonRepository People { get; set; }
}
What do you have now
Almost Done. There is only a few configurations left. But before that lets desscuss what do you have now. Imagine we have a service called PersonService and we have these functionality including many others insise the service.
public class PersonService : IPersonService
{
private readonly ITestUnitOfWork _unitOfWork;
public PersonService(ITestUnitOfWork testUnitOfWork)
{
this._unitOfWork = testUnitOfWork;
}
public async ValueTask Get()
{
// Getting first row of table
var data1 = await _unitOfWork.People.FirstAsync();
// Getting first row of table with specifications, and set cache as true
var data1 = await _unitOfWork.People.FirstAsync(predicate: x => x.CreateDate > DateTime.Now,
orderBy: x => x.OrderByDescending(o => o.CreateDate),
setCache: true,
asNoTracking: AsNoTrackingType.AsNoTracking);
// Getting first row of table
var data2 = await _unitOfWork.People.FirstOrDefaultAsync();
// Getting first row of table with specifications, and set cache as true
var data2 = await _unitOfWork.People.FirstOrDefaultAsync(predicate: x => x.CreateDate > DateTime.Now,
orderBy: x => x.OrderByDescending(o => o.CreateDate),
setCache: true,
asNoTracking: AsNoTrackingType.AsNoTrackingWithIdentityResolution);
// Getting last row of table
var data3 = await _unitOfWork.People.LastAsync();
// Getting last row of table with specifications, and set cache as true
var data4 = await _unitOfWork.People.LastOrDefaultAsync(predicate: x => x.CreateDate > DateTime.Now,
orderBy: x => x.OrderByDescending(o => o.CreateDate),
setCache: true,
asNoTracking: AsNoTrackingType.None);
// Selecting/Searching throughout the table
var data5 = await _unitOfWork.People.FindAsync(predicate: x => x.CreateDate > DateTime.Now,
orderBy: x => x.OrderByDescending(o => o.CreateDate),
setCache: true,
page: 1, pageSize: 100,
asNoTracking: AsNoTrackingType.AsNoTracking);
// Get a row with the id of 12 => Id can be any DATA TYPE
var data6 = await _unitOfWork.People.GetAsync(12, setCache: true);
// Get all data of a table
var data7 = await _unitOfWork.People.GetAllAsync(setCache: true, asNoTracking: AsNoTrackingType.AsNoTracking);
// Get maximum value
var data8 = await _unitOfWork.People.MaxAsync(x => x.Rate, setCache: true);
// Get maximum value according to the predicate
var data8 = await _unitOfWork.People.MaxAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);
// Get minimum value
var data9 = await _unitOfWork.People.MinAsync(x => x.Rate, setCache: true);
// Get minimum value according to the predicate
var data9 = await _unitOfWork.People.MinAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);
// Get Sum of values
var data10 = await _unitOfWork.People.SumAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);
// Get Sum of values
var data11 = await _unitOfWork.People.CountAsync();
// Get Sum of values according to the predicate
var data11 = await _unitOfWork.People.CountAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);
// Get Average of values
var data12 = await _unitOfWork.People.AverageAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);
}
public async Task GetQuery()
{
// You have access to Where clause for any other usage
await _unitOfWork.People.Where(x => x.CreateDate > DateTime.Now).Include(x => x.PersonRules).ToListAsync();
// You can get AsQueryable() for any further implementation
await _unitOfWork.People.AsQueryable().Where(x => x.CreateDate > DateTime.Now).ToListAsync();
// You can even excecute your own T-Sql query
await _unitOfWork.People.FromSqlRaw("SELECT * FROM [dbo].[People]").ToListAsync();
}
public void Remove()
{
_unitOfWork.People.Remove(person);
_unitOfWork.People.RemoveRange(people);
_unitOfWork.SaveChangesAsync();
}
public async Task Add()
{
_unitOfWork.People.Add(person);
_unitOfWork.People.AddRange(people);
await _unitOfWork.People.AddAsync(person);
await _unitOfWork.People.AddRangeAsync(people);
await _unitOfWork.SaveChangesAsync();
}
public async Task Update()
{
var person = await _unitOfWork.People.GetAsync(12);
person.LastModifiedDate = DateTime.Now;
await _unitOfWork.SaveChangesAsync();
}
public async Task DoSometingTransactional()
{
_unitOfWork.BeginTransaction();
try
{
var person = await _unitOfWork.People.GetAsync(12);
person.LastModifiedDate = DateTime.Now;
await _unitOfWork.SaveChangesAsync();
await _unitOfWork.CommitAsync();
}
catch (Exception ex)
{
await _unitOfWork.RollbackAsync();
}
}
}
Easy Peasy caching
With the help of AuxiliaryLibraries.CacheManager we have a easy access to cashing our data here. As mentioned above, we can cache data just by setting setCache as true. If we do that, it means using the cache, if data has already been stored in Redis just fetch and if it didn't get data from Database and then set it to redis.The interesting part here is, there is no need to set the cache key, the naming convention is used according to the Entity Name and the parameters you passed. There might be a big question: When the cached data will update? There is a very easy answer for that and that is when you use _unitOfWork.SaveChangesAsync() caching data will remove. Not all of the cached data, of course, just that part you have updated, inserted, or deleted to or from DB. (The recently affected data) Let's dive into caching a little bit deeper. If you want to use caching out of those functions, you can do as follows, or simply use AuxiliaryLibraries.CacheManager and follow its instructions.
public class PersonService : IPersonService
{
public async Task Caching()
{
// cache key is generating according to the passed parameters to functions. Pass them just like that into the below function
var cacheKey = CacheConventions.Cachekey<Person>(id: 1, baseKey: "Last");
// Or
var cacheKey = CacheConventions.Cachekey<Person>(predicate: x => x.CreateDate > DateTime.Now,
orderBy: x => x.OrderByDescending(o => o.CreateDate));
// Removing value of the cacheKey
_unitOfWork.RefreshCache(cacheKey);
// Replacing the value of the cacheKey by obj
await _unitOfWork.RefreshCache(cacheKey, obj);
// Removing any cached data related to Person
await _unitOfWork.RefreshCache<Person>(setCache: true);
// Removing any cached data related to Person with the predicate
_unitOfWork.RefreshCache<Person>(predicate: x => x.CreateDate > DateTime.Now);
// Or you can simply use
_unitOfWork.People.RefreshCache(cacheKey); // Removing value of the cacheKey
await _unitOfWork.People.RefreshCache(cacheKey, obj); // Replacing the value of the cacheKey by obj
_unitOfWork.People.RefreshCache(); // Removing any cached data related to Person
_unitOfWork.People.RefreshCache(predicate: x => x.CreateDate > DateTime.Now); // Removing any cached data related to Person with the predicate
// Try to get a value from cache
if (_unitOfWork.TryGetCache<Person>(cacheKey, out var person))
{
person.ToString();
}
}
}
Configuration
Now we have to do the last part, Configuration. for this we must register all of our repositories and unit of work into the IOC container.
service.AddScoped<ITestUnitOfWork, TestUnitOfWork>();
service.AddScoped<IPersonRepository, PersonRepository>();
And we have to set use caching as well if we want to use caching. Otherwise, it is not necessary.
service.UseCache(configuration);
//add this to appsettings
"CacheConfiguration": {
"AbsoluteExpirationInHours": 1,
"SlidingExpirationInMinutes": 30,
"Host": "111.111.111.111",
"Port": "80",
"Password": "redis",
"DatabaseID": 1
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- AuxiliaryLibraries.CacheManager (>= 1.0.2)
- Microsoft.EntityFrameworkCore.Relational (>= 7.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.