AuxiliaryLibraries.GenericRepository.Core 1.0.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package AuxiliaryLibraries.GenericRepository.Core --version 1.0.3                
NuGet\Install-Package AuxiliaryLibraries.GenericRepository.Core -Version 1.0.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AuxiliaryLibraries.GenericRepository.Core" Version="1.0.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AuxiliaryLibraries.GenericRepository.Core --version 1.0.3                
#r "nuget: AuxiliaryLibraries.GenericRepository.Core, 1.0.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install AuxiliaryLibraries.GenericRepository.Core as a Cake Addin
#addin nuget:?package=AuxiliaryLibraries.GenericRepository.Core&version=1.0.3

// Install AuxiliaryLibraries.GenericRepository.Core as a Cake Tool
#tool nuget:?package=AuxiliaryLibraries.GenericRepository.Core&version=1.0.3                

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. Furtheremore, 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, becuase you can focus on implementing logic of your project and leave the Data Access Layar to this library. You have to do a few steps as describes below. EntityFramewok Core is used in this library and if you choose another types of ORM this library might not usefull fore you.

How it works

There are a few base classes inside the library, you should create one interface and one repository class fr 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 repositorties. After that you must register your classes to your IOC container.

How to use

Lets imagine we have one entity. In real projects yo will have more than that. Do these steps for all of them.

Table - Entity

public partial class Currency
{
    public long Id { get; set; }
    public string Title { get; set; } = null!;
    public string Abbreviation { get; set; } = null!;
    public DateTime CreateDate { get; set; }
    public DateTime LastModifiedDate { get; set; }
}

Repository

Now you should create one interface and one Repository class as follows:

Currency Repository Interface

There is a base interface called IRepository. Create an interface and inherit it from IRepository<TEntity>:

public interface ICurrencyRepository : IRepository<Currency>
{
    // For default you do not need to add anything here.
}

Currency Repository

There is a base interface called Repository. Create a class and inherit it from Repository<TEntity> and ICurrencyRepository:

public class CurrencyRepository : Repository<Currency>, ICurrencyRepository
{
    // TestDbContext is the name of your DbContext, Replace it with your own DbContext name
    private TestDbContext TestDbContext => Context as TestDbContext;

    public CurrencyRepository(TestDbContext context, ICacheService cacheService) : base(context, cacheService)
    {
      // For default you do not need to add anything here.
    }
}

If you need to add any other functionality to your repositoreis you can do like this

Currency Repository Interface

public interface ICurrencyRepository : IRepository<Currency>
{
    Task<Currency> GetLastSourceAsync(bool setCache = false);
}

Currency Repository

public class CurrencyRepository : Repository<Currency>, ICurrencyRepository
{
    // TestDbContext is the name of your DbContext, Replace it with your own DbContext name
    private TestDbContext TestDbContext => Context as TestDbContext;

    public CurrencyRepository(TestDbContext context, ICacheService cacheService) : base(context, cacheService)
    {
        public virtual async Task<Currency> GetLastSourceAsync(bool setCache = false)
        {
            var cacheKey = CacheConventions.Cachekey<Currency>(id: 1, baseKey: "Last");
            if (!CacheService.TryGet(cacheKey, out Currency cachedItem))
            {
                cachedItem = await TestDbContext.Currencies.OrderByDescending(x => x.CreateDate).FirstOrDefaultAsync(x => !string.IsNullOrEmpty(x.Title));
                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
{
    ICurrencyRepository Currencies { 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,
        ICurrencyRepository currencyRepository
    ) : base(context, cacheService)
    {
        Currencies = currencyRepository;
    }

    public ICurrencyRepository Currencies { 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 CurrencyService and we have these functionality including many others insise the service.

public class CurrencyService : ICurrencyService
{
    private readonly ITestUnitOfWork _unitOfWork;

    public CurrencyService(ITestUnitOfWork testUnitOfWork)
    {
        this._unitOfWork = testUnitOfWork;
    }

    public async ValueTask Get()
    {
        // Getting first row of table
        var data1 = await _unitOfWork.Currencies.FirstAsync();
        // Getting first row of table with specifications, and set cache as true
        var data1 = await _unitOfWork.Currencies.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.Currencies.FirstOrDefaultAsync();
        // Getting first row of table with specifications, and set cache as true
        var data2 = await _unitOfWork.Currencies.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.Currencies.LastAsync();
        // Getting last row of table with specifications, and set cache as true
        var data4 = await _unitOfWork.Currencies.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.Currencies.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.Currencies.GetAsync(12, setCache: true);

        // Get all data of a table
        var data7 = await _unitOfWork.Currencies.GetAllAsync(setCache: true, asNoTracking: AsNoTrackingType.AsNoTracking);

        // Get maximum value
        var data8 = await _unitOfWork.Currencies.MaxAsync(x => x.Rate, setCache: true);
        // Get maximum value according to the predicate
        var data8 = await _unitOfWork.Currencies.MaxAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);

        // Get minimum value
        var data9 = await _unitOfWork.Currencies.MinAsync(x => x.Rate, setCache: true);
        // Get minimum value according to the predicate
        var data9 = await _unitOfWork.Currencies.MinAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);

        // Get Sum of values
        var data10 = await _unitOfWork.Currencies.SumAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);

        // Get Sum of values
        var data11 = await _unitOfWork.Currencies.CountAsync();
        // Get Sum of values according to the predicate
        var data11 = await _unitOfWork.Currencies.CountAsync(predicate: x => x.CreateDate > DateTime.Now, selector: x => x.Rate, setCache: true);

        // Get Average of values
        var data12 = await _unitOfWork.Currencies.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.Currencies.Where(x => x.CreateDate > DateTime.Now).Include(x => x.CurrencyRules).ToListAsync();
        // You can get AsQueryable() for any further implementation
        await _unitOfWork.Currencies.AsQueryable().Where(x => x.CreateDate > DateTime.Now).ToListAsync();
        // You can even excecute your own T-Sql query
        await _unitOfWork.Currencies.FromSqlRaw("SELECT * FROM [dbo].[Currency]").ToListAsync();
    }

    public void Remove()
    {
        _unitOfWork.Currencies.Remove(currency);
        _unitOfWork.Currencies.RemoveRange(currencies);
        _unitOfWork.SaveChangesAsync();
    }

    public async Task Add()
    {
        _unitOfWork.Currencies.Add(currency);
        _unitOfWork.Currencies.AddRange(currencies);

        await _unitOfWork.Currencies.AddAsync(currency);
        await _unitOfWork.Currencies.AddRangeAsync(currencies);

        await _unitOfWork.SaveChangesAsync();
    }

    public async Task Update()
    {
        var currency = await _unitOfWork.Currencies.GetAsync(12);
        currency.LastModifiedDate = DateTime.Now;
        await _unitOfWork.SaveChangesAsync();
    }

    public async Task DoSometingTransactional()
    {
        _unitOfWork.BeginTransaction();
        try
        {
            var currency = await _unitOfWork.Currencies.GetAsync(12);
            currency.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 use cache, if data has already stored in Redis just fetch and if it didn't get data from Database and then set it to redis. The intersting part here is, there is no need to set the cache key, naming convention is used according to the EntityName 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() cahing data will remove. Not all of data that cached, just that part you have updated, inserted, or deleted to db. Let's dive into caching a little bit deeper. If you want to use caching out od=f those function, you can do as follows, or simply use AuxiliaryLibraries.CacheManager and follow its instructions.

public class CurrencyService : ICurrencyService
{
    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<Currency>(id: 1, baseKey: "Last");
        // Or
        var cacheKey = CacheConventions.Cachekey<Currency>(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 Currency
        await _unitOfWork.RefreshCache<Currency>(setCache: true);
        // Removing any cached data related to Currency with the predicate
        _unitOfWork.RefreshCache<Currency>(predicate: x => x.CreateDate > DateTime.Now);
        // Or you can simply use 
        _unitOfWork.Currencies.RefreshCache(cacheKey); // Removing value of the cacheKey
        await _unitOfWork.Currencies.RefreshCache(cacheKey, obj); // Replacing the value of the cacheKey by obj
        _unitOfWork.Currencies.RefreshCache(); // Removing any cached data related to Currency
        _unitOfWork.Currencies.RefreshCache(predicate: x => x.CreateDate > DateTime.Now); // Removing any cached data related to Currency with the predicate
        // Try to get a value from cache
        if (_unitOfWork.TryGetCache<Currency>(cacheKey, out var currency))
        {
            currency.ToString();
        }
    }
}

Configuration

Now we have to do the last part, Configuration. for this we must register all of our repositories and unit of worlk into IOC container.

service.AddScoped<ITestUnitOfWork, TestUnitOfWork>();
service.AddScoped<ICurrencyRepository, CurrencyRepository>();

And we have to set use cache 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.7 131 4/2/2024
1.0.6 319 2/18/2023
1.0.5 254 2/7/2023
1.0.4 268 2/7/2023
1.0.3 290 2/5/2023
1.0.2 301 2/2/2023
1.0.1 260 2/2/2023
1.0.0 289 1/30/2023