using LANCommander.Launcher.Data; using LANCommander.Launcher.Data.Models; using LANCommander.Launcher.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using System.Linq.Expressions; namespace LANCommander.Launcher.Services { public abstract class BaseDatabaseService : BaseService where T : BaseModel { protected DatabaseContext Context { get; set; } public BaseDatabaseService(DatabaseContext dbContext, ILogger logger) : base(logger) { Context = dbContext; } public virtual async Task> GetAsync() { return await Query(x => true).ToListAsync(); } public virtual async Task GetAsync(Guid id) { return await Context.Set().FindAsync(id); } public virtual async Task FirstOrDefaultAsync(Expression> predicate) { return await Context.Set().FirstOrDefaultAsync(predicate); } public virtual IQueryable Query(Expression> predicate) { return Context.Set().Where(predicate); } public virtual async Task ExistsAsync(Guid id) => await Context.Set().AnyAsync(x => x.Id == id); public virtual async Task ExistsAsync(Expression> predicate) => await Context.Set().AnyAsync(predicate); public virtual async Task AddAsync(T entity) { var result = await Context.Set().AddAsync(entity); entity = result.Entity; if (Context.Database.CurrentTransaction == null) await Context.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 Query(predicate).FirstOrDefaultAsync(); if (existing == null) { entity = await AddAsync(entity); return new ExistingEntityResult { Value = entity, Existing = false, }; } else { return new ExistingEntityResult { Value = entity, Existing = true, }; } } public virtual async Task UpdateAsync(T entity) { var existing = await GetAsync(entity.Id); Context.Entry(existing).CurrentValues.SetValues(entity); entity = Context.Update(existing).Entity; if (Context.Database.CurrentTransaction == null) await Context.SaveChangesAsync(); return entity; } public virtual async Task SyncRelatedCollectionAsync( T entity, Expression>> navigationProperty, IEnumerable records, Func>> matchExpression, Action updateAction) where TChild : class { var collection = navigationProperty.Compile().Invoke(entity); var matchedChildren = new HashSet(); foreach (var record in records) { var matchPredicate = matchExpression(record); var existingChild = collection.FirstOrDefault(matchPredicate.Compile()); if (existingChild == null) { existingChild = await Context.Set() .FirstOrDefaultAsync(matchPredicate); } if (existingChild != null) { if (!collection.Contains(existingChild)) collection.Add(existingChild); updateAction(existingChild, record); matchedChildren.Add(existingChild); } else { var newChild = Activator.CreateInstance(); updateAction(newChild, record); collection.Add(existingChild); matchedChildren.Add(existingChild); } } var toDelete = collection.Where(child => !matchedChildren.Contains(child)); foreach (var child in toDelete) { collection.Remove(child); Context.Remove(child); } await Context.SaveChangesAsync(); } public virtual async Task DeleteAsync(T entity) { Context.Set().Remove(entity); if (Context.Database.CurrentTransaction == null) await Context.SaveChangesAsync(); } } }