-1

My project is using Entity Framework Core, SQLite, Avalonia and Automapper (it errors before the mappings). After my program started and done configuring and starting another program it will error after sitting for 20 minutes. It doesn't matter if the processes it spins up are running or not. There is no database call to the SQLite database when this happens and since there is no information retrieved it errors when I try and get the info from my context.

Base class for database calls:

public  class CoreEntity<TEntity, TDto, TContext> : ICoreEntity<TEntity> where TEntity : ICoreEntity<TEntity>
{

    public static IMapper mapper = AutoMapperCore.mapper!;

    public  TDto Get(int id)
    {
        using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
        var entity = context.Set<TEntity>().AsNoTracking().Where(x=>x.Id == id).FirstOrDefault() ?? throw new Exception(string.Format("{0} not found", typeof(TEntity).Name));
        return mapper.Map<TEntity, TDto>(entity);

    }
    public bool UpdateNoSubEntites(TDto dto)
    {
        var entity = updateEntityNoSubEntites(dto);
        using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
        context.Update(entity);
        context.SaveChanges();
        return false;
    }

    public  bool Update(TDto dto)
    {
        try
        {
            var entity = updateEntity(dto);
            using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
            context.Update(entity);
            context.SaveChanges();
            return true;
        }
        catch (Exception ex)
        {
            return false;

        }

    }
    public  bool Delete(int id)
    {
        try
        {
            using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
            var entity = context.Set<TEntity>().Where(x => x.Id == id).FirstOrDefault() ?? throw new Exception(string.Format("{0} not found", typeof(TEntity).Name));
            context.Remove(entity!);
            context.SaveChanges();
            return true;
        }
        catch(Exception ex)
        {
            return false;
        }

    }
    public virtual  IList<TDto> GetAll()
    {
        using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
        var entities = context.Set<TEntity>().AsNoTracking().ToList() ?? throw new Exception(string.Format("{0} not found", typeof(TEntity).Name));
        var dtos = mapper.Map<IEnumerable<TEntity>, IEnumerable<TDto>>(entities).ToList();
        return dtos;
    }
    public  bool Add(TDto dto)
    {
        using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
        var entity = mapper.Map<TEntity>(dto);
        var temp = context.Add(entity!);
        context.SaveChanges();
        if (temp != null)
            return true;
        return false;
    }

    private  TEntity updateEntity(TDto dto)
    {
        var newEntity = mapper.Map<TEntity>(dto);
        using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
        var entity = context.Set<TEntity>().Where(x => x.Id == newEntity.Id).FirstOrDefault() ?? throw new Exception(string.Format("{0} not found", typeof(TEntity).Name));
        entity = newEntity;
        return entity;
    }

    private  TEntity updateEntityNoSubEntites(TDto dto)
    {
        var newEntity = mapper.Map<TEntity>(dto);
        using var context = SimulatorContextFactory.CreateDbContext(typeof(TContext));
        var entity = context.Set<TEntity>().Where(x => x.Id == newEntity.Id).FirstOrDefault() ?? throw new Exception(string.Format("{0} not found", typeof(TEntity).Name));
        Type entityType = typeof(TEntity);
        foreach(var property in entityType.GetProperties())
        {
            Type propertyType = property.PropertyType;
            string propertyName = property.Name;
            if(IsSimple(propertyType) && !propertyName.ToLower().Contains("id"))
            {
                var newValue = property.GetValue(newEntity);
                property.SetValue(entity, newValue, null);
            }
        }
        return entity;
    }
    private static bool IsSimple(Type type)
    {
        return type.IsPrimitive
            || type.IsEnum
            || type.Equals(typeof(string))
            || type.Equals(typeof(decimal));
    }

Entities with context:

public class BrandDetail : CoreEntity<BrandDetail, BrandDetailDto, BrandDetailContext>
{

    public string BrandShortName { get; set; } = string.Empty;
    public string BrandImagePath { get; set; } = string.Empty;
    public string BrandLogoPath { get; set; } = string.Empty;
    public string BannerImagePath { get; set; } = string.Empty;
    public string MainUiColor { get; set; } = string.Empty;
    public string BootAnimation { get; set; } = string.Empty;
    public  List<Vehicle> Vehicles { get; set; } = new();
    public  List<Implement> Implements { get; set; } = new();
    public List<Display> Displays { get; set; } = new();
    public string Installed { get; set; } = string.Empty;
    public bool IsInstalled { get { return Installed?.ToLower() == "true"; } }

   // public int Translation_BrandNameId { get; set; }
    public virtual Translation Translation_BrandName { get; set; } = new Translation() { English = "" };

}

public class BrandDetailProfile : BaseProfile

public class BrandDetailContext : BaseContext
{
    public BrandDetailContext(string dbPath) : base(dbPath)
    {
    }

    public required DbSet<BrandDetail> BrandDetails { get; set; }
    public DbSet<Vehicle> Vehicles { get; set; }

    public DbSet<Implement> Implements { get; set; }

    public DbSet<Display> Displays { get; set; }

    public DbSet<Translation> Translations { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BrandDetail>();
        modelBuilder.Entity<BrandDetail>().HasMany(x=> x.Vehicles).WithOne(x=>x.Brand).HasForeignKey(x=>x.BrandId).IsRequired();
        modelBuilder.Entity<BrandDetail>().HasMany(x => x.Implements).WithOne(x => x.Brand).HasForeignKey(x => x.BrandId).IsRequired();
        modelBuilder.Entity<BrandDetail>().HasMany(x => x.Displays).WithOne(x => x.Brand).HasForeignKey(x => x.BrandId).IsRequired();
        modelBuilder.Entity<BrandDetail>().Navigation(x => x.Vehicles).AutoInclude();
        modelBuilder.Entity<BrandDetail>().Navigation(x=>x.Displays).AutoInclude();
        modelBuilder.Entity<BrandDetail>().Navigation(x => x.Translation_BrandName).AutoInclude();
        modelBuilder.Entity<Vehicle>().Navigation(x=> x.Translation_VehicleName).AutoInclude();
        modelBuilder.Entity<Display>().Navigation(x=>x.Translation_DisplayName).AutoInclude();
        base.OnModelCreating(modelBuilder);
    }
}

This only happens after around 20 minutes and breaks on the first new call to the database. The logger doesn't show anything that I've added to the BaseContext class here:

public abstract class BaseContext : DbContext
{
    private readonly StreamWriter _logStream = new StreamWriter("mylog1.txt", append: true);
    private string _dbPath { get; }
    protected BaseContext(string dbPath)
    {
        _dbPath = dbPath;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite($"Data Source={_dbPath}")
        .LogTo(_logStream.WriteLine);

    public override void Dispose()
    {

        base.Dispose();
        _logStream.Dispose();
    }

    public override async ValueTask DisposeAsync()
    {
        await base.DisposeAsync();
        await _logStream.DisposeAsync();
    }

}

Factory that creates the context:

public static class SimulatorContextFactory
{
    private static bool isInitialized = false;
    private static string connectionString = string.Empty;


    public static  void Initialize(string connectionStringInput)
    {
        if (isInitialized)
        {
            throw new InvalidOperationException("The DbContextFactory has already been initialized.");
        }

        connectionString = connectionStringInput;
        isInitialized = true;
    }

    public static DbContext CreateDbContext(Type type)

    {

        if (!isInitialized)
        {
            throw new InvalidOperationException("The DbContextFactory has not been initialized.");
        }
        DbContext? context = Activator.CreateInstance(type, new object[] { connectionString }) as DbContext;

        if(context != null)
        {
            context.Database.EnsureCreated();
            return context;
        }
        throw new Exception("no context found ");

    }
}

The database call initially didn't use generics. I've tried adding garbage collecting on the dispose. I don't see memory leaks in Visual Studio.

user4157124
  • 2,809
  • 13
  • 27
  • 42
  • Have you tried removing each of the listed dependencies (packages) one by one to see if any are the culprit? That might not outright solve your problem, but it could narrow down the culprit dependency, and you can then possibly code around that dependency. True, you may lose some of the handy shortcuts the dependency provides, but such is a typical work-around. As a reminder, test-remove the dependencies on a copy of the app, not the original. Or make a simplified mini-app. – FloverOwe Aug 10 '23 at 00:42
  • Thanks for the suggestion! For better or worse this bug hasn't been labeled as a high priority so I don't know when I'll get back to this, but it's a good place to start if I have to pick it back up – paul hagerling Aug 11 '23 at 14:40

0 Answers0