using LANCommander.Server.Data; using LANCommander.Server.Data.Models; using LANCommander.Server.Models; using LANCommander.Server.Services.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.Extensions.Logging; using System.Linq.Expressions; using ZiggyCreatures.Caching.Fusion; namespace LANCommander.Server.Services { public abstract class BaseDatabaseService : BaseService, IBaseDatabaseService where T : class, IBaseModel { protected readonly IFusionCache Cache; public Repository Repository { get; set; } public BaseDatabaseService(ILogger logger, IFusionCache cache, Repository repository) : base(logger) { Cache = cache; Repository = repository; } public IBaseDatabaseService Include(Expression> includeExpression) { Repository.Include(includeExpression); return this; } public IBaseDatabaseService DisableTracking() { Repository.AsNoTracking(); return this; } public virtual async Task> GetAsync() { return await Cache.GetOrSetAsync($"{typeof(T).FullName}:Get", async _ => { return await GetAsync(x => true); }, TimeSpan.FromSeconds(30)); } public virtual async Task> GetAsync() { return await GetAsync(x => true); } public virtual async Task GetAsync(Guid id) { return await Repository.FindAsync(id); } public virtual async Task GetAsync(Guid id) { return await Repository.FindAsync(id); } public virtual async Task> GetAsync(Expression> predicate) { Logger?.LogDebug("Getting data from context ID {ContextId}", Repository.Context.ContextId); var results = await Repository.GetAsync(predicate); Logger?.LogDebug("Done getting data from context ID {ContextId}", Repository.Context.ContextId); return results; } public virtual async Task> GetAsync(Expression> predicate) { Logger?.LogDebug("Getting data from context ID {ContextId}", Repository.Context.ContextId); var results = await Repository.GetAsync(predicate); Logger?.LogDebug("Done getting data from context ID {ContextId}", Repository.Context.ContextId); return results; } public virtual async Task FirstAsync(Expression> predicate) { return await Repository.FirstAsync(predicate); } public virtual async Task FirstAsync(Expression> predicate) { return await Repository.FirstAsync(predicate); } public virtual async Task FirstAsync(Expression> predicate, Expression> orderKeySelector) { return await Repository.FirstAsync(predicate, orderKeySelector); } public virtual async Task FirstAsync(Expression> predicate, Expression> orderKeySelector) { return await Repository.FirstAsync(predicate, orderKeySelector); } public virtual async Task FirstOrDefaultAsync(Expression> predicate) { return await Repository.FirstOrDefaultAsync(predicate); } public virtual async Task FirstOrDefaultAsync(Expression> predicate) { return await Repository.FirstOrDefaultAsync(predicate); } public virtual async Task FirstOrDefaultAsync(Expression> predicate, Expression> orderKeySelector) { return await Repository.FirstOrDefaultAsync(predicate, orderKeySelector); } public virtual async Task FirstOrDefaultAsync(Expression> predicate, Expression> orderKeySelector) { return await Repository.FirstOrDefaultAsync(predicate, orderKeySelector); } public virtual async Task ExistsAsync(Guid id) { return GetAsync(id) != null; } public virtual async Task AddAsync(T entity) { entity = await Repository.AddAsync(entity); await Repository.SaveChangesAsync(); return entity; } /// /// Adds an entity to the database if it does exist as dictated by the predicate /// /// Qualifier expressoin /// Entity to add /// Newly created or existing entity public virtual async Task> AddMissingAsync(Expression> predicate, T entity) { var existing = await Repository.FirstOrDefaultAsync(predicate); if (existing == null) { await Cache.ExpireAsync($"{typeof(T).FullName}:Get"); entity = await Repository.AddAsync(entity); await Repository.SaveChangesAsync(); return new ExistingEntityResult { Value = entity, Existing = false }; } else { return new ExistingEntityResult { Value = existing, Existing = true }; } } public virtual async Task UpdateAsync(T entity) { await Cache.ExpireAsync($"{typeof(T).FullName}:Get"); entity = await Repository.UpdateAsync(entity); await Repository.SaveChangesAsync(); return entity; } public virtual async Task DeleteAsync(T entity) { await Cache.ExpireAsync($"{typeof(T).FullName}:Get"); Repository.Delete(entity); await Repository.SaveChangesAsync(); } } }