Got the new DB structure in place

pull/3241/head
tidusjar 5 years ago
parent d13a1865ea
commit 37aca4e423

@ -135,11 +135,11 @@ namespace Ombi.DependencyInjection
}
public static void RegisterStore(this IServiceCollection services) {
services.AddDbContext<OmbiContext>();
//services.AddDbContext<OmbiContext>();
services.AddDbContext<SettingsContext>();
services.AddDbContext<ExternalContext>();
services.AddScoped<IOmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
//services.AddScoped<OmbiContext, OmbiContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
services.AddScoped<ISettingsContext, SettingsContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
services.AddScoped<IExternalContext, ExternalContext>(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6
services.AddScoped<ISettingsRepository, SettingsJsonRepository>();

@ -1,44 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Context
{
public interface IOmbiContext : IDbContext
{
//DbSet<PlexServerContent> PlexServerContent { get; set; }
//DbSet<PlexEpisode> PlexEpisode { get; set; }
DbSet<GlobalSettings> Settings { get; set; }
//DbSet<RadarrCache> RadarrCache { get; set; }
//DbSet<EmbyContent> EmbyContent { get; set; }
//DbSet<EmbyEpisode> EmbyEpisode { get; set; }
DbSet<NotificationTemplates> NotificationTemplates { get; set; }
DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }
DbSet<Votes> Votes { get; set; }
void Seed();
DbSet<Audit> Audit { get; set; }
DbSet<MovieRequests> MovieRequests { get; set; }
DbSet<AlbumRequest> AlbumRequests { get; set; }
DbSet<TvRequests> TvRequests { get; set; }
DbSet<ChildRequests> ChildRequests { get; set; }
DbSet<Issues> Issues { get; set; }
DbSet<IssueCategory> IssueCategories { get; set; }
DbSet<Tokens> Tokens { get; set; }
DbSet<SonarrCache> SonarrCache { get; set; }
//DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
//DbSet<CouchPotatoCache> CouchPotatoCache { get; set; }
//DbSet<SickRageCache> SickRageCache { get; set; }
//DbSet<LidarrArtistCache> LidarrArtistCache { get; set; }
//DbSet<LidarrAlbumCache> LidarrAlbumCache { get; set; }
//DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
DbSet<RequestLog> RequestLogs { get; set; }
DbSet<RecentlyAddedLog> RecentlyAddedLogs { get; set; }
DbSet<RequestSubscription> RequestSubscription { get; set; }
}
}

@ -10,19 +10,28 @@ using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Context
{
public sealed class OmbiContext : IdentityDbContext<OmbiUser>, IOmbiContext
public abstract class OmbiContext : IdentityDbContext<OmbiUser>
{
private static bool _created;
public OmbiContext()
protected OmbiContext(DbContextOptions<OmbiContext> options) : base(options)
{
if (_created) return;
_created = true;
Database.SetCommandTimeout(60);
Database.Migrate();
}
/// <summary>
/// This allows a sub class to call the base class 'DbContext' non typed constructor
/// This is need because instances of the subclasses will use a specific typed DbContextOptions
/// which can not be converted into the parameter in the above constructor
/// </summary>
/// <param name="options"></param>
protected OmbiContext(DbContextOptions options)
: base(options)
{
}
public DbSet<NotificationTemplates> NotificationTemplates { get; set; }
public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }
public DbSet<PlexServerContent> PlexServerContent { get; set; }
@ -60,33 +69,6 @@ namespace Ombi.Store.Context
public DbSet<UserQualityProfiles> UserQualityProfileses { get; set; }
public DbSet<RequestQueue> RequestQueue { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var i = StoragePathSingleton.Instance;
if (string.IsNullOrEmpty(i.StoragePath))
{
i.StoragePath = string.Empty;
}
optionsBuilder.UseSqlite($"Data Source={Path.Combine(i.StoragePath, "Ombi.db")}");
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PlexServerContent>().HasMany(x => x.Episodes)
.WithOne(x => x.Series)
.HasPrincipalKey(x => x.Key)
.HasForeignKey(x => x.GrandparentKey);
builder.Entity<EmbyEpisode>()
.HasOne(p => p.Series)
.WithMany(b => b.Episodes)
.HasPrincipalKey(x => x.EmbyId)
.HasForeignKey(p => p.ParentId);
base.OnModelCreating(builder);
}
public void Seed()
{

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore;
using Ombi.Store.Entities;
namespace Ombi.Store.Context
{
public sealed class OmbiSqliteContext : OmbiContext
{
private static bool _created;
public OmbiSqliteContext(DbContextOptions<OmbiSqliteContext> options) : base(options)
{
if (_created) return;
_created = true;
Database.SetCommandTimeout(60);
Database.Migrate();
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PlexServerContent>().HasMany(x => x.Episodes)
.WithOne(x => x.Series)
.HasPrincipalKey(x => x.Key)
.HasForeignKey(x => x.GrandparentKey);
builder.Entity<EmbyEpisode>()
.HasOne(p => p.Series)
.WithMany(b => b.Episodes)
.HasPrincipalKey(x => x.EmbyId)
.HasForeignKey(p => p.ParentId);
base.OnModelCreating(builder);
}
}
}

@ -9,12 +9,12 @@ namespace Ombi.Store.Repository
{
public class AuditRepository : IAuditRepository
{
public AuditRepository(IOmbiContext ctx)
public AuditRepository(OmbiContext ctx)
{
Ctx = ctx;
}
private IOmbiContext Ctx { get; }
private OmbiContext Ctx { get; }
public async Task Record(AuditType type, AuditArea area, string description)

@ -13,7 +13,7 @@ using Polly;
namespace Ombi.Store.Repository
{
public class BaseRepository<T, U> : IRepository<T> where T : Entity where U : IDbContext
public class BaseRepository<T, U> : IRepository<T> where T : Entity where U : DbContext
{
public BaseRepository(U ctx)
{

@ -38,12 +38,12 @@ namespace Ombi.Store.Repository
public class EmbyContentRepository : ExternalRepository<EmbyContent>, IEmbyContentRepository
{
public EmbyContentRepository(IExternalContext db):base(db)
public EmbyContentRepository(ExternalContext db):base(db)
{
Db = db;
}
private IExternalContext Db { get; }
private ExternalContext Db { get; }
public async Task<EmbyContent> GetByImdbId(string imdbid)

@ -3,9 +3,9 @@ using Ombi.Store.Entities;
namespace Ombi.Store.Repository
{
public class ExternalRepository<T> : BaseRepository<T, IExternalContext>, IExternalRepository<T> where T : Entity
public class ExternalRepository<T> : BaseRepository<T, ExternalContext>, IExternalRepository<T> where T : Entity
{
public ExternalRepository(IExternalContext ctx) : base(ctx)
public ExternalRepository(ExternalContext ctx) : base(ctx)
{
}
}

@ -11,12 +11,12 @@ namespace Ombi.Store.Repository
{
public class NotificationTemplatesRepository : INotificationTemplatesRepository
{
public NotificationTemplatesRepository(IOmbiContext ctx)
public NotificationTemplatesRepository(OmbiContext ctx)
{
Db = ctx;
}
private IOmbiContext Db { get; }
private OmbiContext Db { get; }
public IQueryable<NotificationTemplates> All()
{

@ -39,12 +39,12 @@ namespace Ombi.Store.Repository
public class PlexServerContentRepository : ExternalRepository<PlexServerContent>, IPlexContentRepository
{
public PlexServerContentRepository(IExternalContext db) : base(db)
public PlexServerContentRepository(ExternalContext db) : base(db)
{
Db = db;
}
private IExternalContext Db { get; }
private ExternalContext Db { get; }
public async Task<bool> ContentExists(string providerId)

@ -3,9 +3,9 @@ using Ombi.Store.Entities;
namespace Ombi.Store.Repository
{
public class Repository<T> : BaseRepository<T,IOmbiContext>, IRepository<T> where T : Entity
public class Repository<T> : BaseRepository<T, OmbiContext>, IRepository<T> where T : Entity
{
public Repository(IOmbiContext ctx) : base(ctx)
public Repository(OmbiContext ctx) : base(ctx)
{
}
}

@ -8,7 +8,7 @@ namespace Ombi.Store.Repository.Requests
{
public interface ITvRequestRepository
{
IOmbiContext Db { get; }
OmbiContext Db { get; }
Task<TvRequests> Add(TvRequests request);
Task<ChildRequests> AddChild(ChildRequests request);
Task Delete(TvRequests request);

@ -11,12 +11,12 @@ namespace Ombi.Store.Repository.Requests
{
public class MovieRequestRepository : Repository<MovieRequests>, IMovieRequestRepository
{
public MovieRequestRepository(IOmbiContext ctx) : base(ctx)
public MovieRequestRepository(OmbiContext ctx) : base(ctx)
{
Db = ctx;
}
private IOmbiContext Db { get; }
private OmbiContext Db { get; }
public async Task<MovieRequests> GetRequestAsync(int theMovieDbId)
{

@ -11,12 +11,12 @@ namespace Ombi.Store.Repository.Requests
{
public class MusicRequestRepository : Repository<AlbumRequest>, IMusicRequestRepository
{
public MusicRequestRepository(IOmbiContext ctx) : base(ctx)
public MusicRequestRepository(OmbiContext ctx) : base(ctx)
{
Db = ctx;
}
private IOmbiContext Db { get; }
private OmbiContext Db { get; }
public Task<AlbumRequest> GetRequestAsync(string foreignAlbumId)
{

@ -8,14 +8,14 @@ using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests
{
public class TvRequestRepository : BaseRepository<TvRequests, IOmbiContext>, ITvRequestRepository
public class TvRequestRepository : BaseRepository<TvRequests, OmbiContext>, ITvRequestRepository
{
public TvRequestRepository(IOmbiContext ctx) : base(ctx)
public TvRequestRepository(OmbiContext ctx) : base(ctx)
{
Db = ctx;
}
public IOmbiContext Db { get; }
public OmbiContext Db { get; }
public async Task<TvRequests> GetRequestAsync(int tvDbId)
{

@ -8,14 +8,14 @@ using Ombi.Helpers;
namespace Ombi.Store.Repository
{
public class TokenRepository : BaseRepository<Tokens, IOmbiContext>, ITokenRepository
public class TokenRepository : BaseRepository<Tokens, OmbiContext>, ITokenRepository
{
public TokenRepository(IOmbiContext db) : base(db)
public TokenRepository(OmbiContext db) : base(db)
{
Db = db;
}
private IOmbiContext Db { get; }
private OmbiContext Db { get; }
public async Task CreateToken(Tokens token)
{

@ -36,12 +36,12 @@ namespace Ombi.Store.Repository
{
//public class UserRepository : IUserRepository
//{
// public UserRepository(IOmbiContext ctx)
// public UserRepository(OmbiContext ctx)
// {
// Db = ctx;
// }
// private IOmbiContext Db { get; }
// private OmbiContext Db { get; }
// public async Task<User> GetUser(string username)
// {

@ -0,0 +1,26 @@
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Ombi.Helpers;
using Ombi.Store.Context;
namespace Ombi
{
public static class DatabaseExtensions
{
public static void ConfigureDatabases(this IServiceCollection services)
{
services.AddDbContext<OmbiContext, OmbiSqliteContext>(ConfigureSqlite);
}
private static void ConfigureSqlite(DbContextOptionsBuilder options)
{
var i = StoragePathSingleton.Instance;
if (string.IsNullOrEmpty(i.StoragePath))
{
i.StoragePath = string.Empty;
}
options.UseSqlite($"Data Source={Path.Combine(i.StoragePath, "Ombi.db")}");
}
}
}

@ -79,6 +79,7 @@
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.2.0" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.0.0-alpha6-79" />
<PackageReference Include="ncrontab" Version="3.3.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.6" />
<PackageReference Include="Serilog" Version="2.7.1" />
<PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" />
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />

@ -50,7 +50,7 @@ namespace Ombi
instance.StoragePath = storagePath ?? string.Empty;
// Check if we need to migrate the settings
DeleteSchedules();
CheckAndMigrate();
//CheckAndMigrate();
var ctx = new SettingsContext();
var config = ctx.ApplicationConfigurations.ToList();
var url = config.FirstOrDefault(x => x.Type == ConfigurationTypes.Url);
@ -132,156 +132,156 @@ namespace Ombi
}
}
/// <summary>
/// This is to remove the Settings from the Ombi.db to the "new"
/// OmbiSettings.db
///
/// Ombi is hitting a limitation with SQLite where there is a lot of database activity
/// and SQLite does not handle concurrency at all, causing db locks.
///
/// Splitting it all out into it's own DB helps with this.
/// </summary>
private static void CheckAndMigrate()
{
var doneGlobal = false;
var doneConfig = false;
var ombi = new OmbiContext();
var settings = new SettingsContext();
try
{
using (var tran = settings.Database.BeginTransaction())
{
if (ombi.Settings.Any() && !settings.Settings.Any())
{
// OK migrate it!
var allSettings = ombi.Settings.ToList();
settings.Settings.AddRange(allSettings);
doneGlobal = true;
}
// Check for any application settings
if (ombi.ApplicationConfigurations.Any() && !settings.ApplicationConfigurations.Any())
{
// OK migrate it!
var allSettings = ombi.ApplicationConfigurations.ToList();
settings.ApplicationConfigurations.AddRange(allSettings);
doneConfig = true;
}
settings.SaveChanges();
tran.Commit();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
using (var tran = ombi.Database.BeginTransaction())
{
// Now delete the old stuff
if (doneGlobal)
ombi.Database.ExecuteSqlCommand("DELETE FROM GlobalSettings");
if (doneConfig)
ombi.Database.ExecuteSqlCommand("DELETE FROM ApplicationConfiguration");
tran.Commit();
}
// Now migrate all the external stuff
var external = new ExternalContext();
try
{
using (var tran = external.Database.BeginTransaction())
{
if (ombi.PlexEpisode.Any())
{
external.PlexEpisode.AddRange(ombi.PlexEpisode.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM PlexEpisode");
}
if (ombi.PlexSeasonsContent.Any())
{
external.PlexSeasonsContent.AddRange(ombi.PlexSeasonsContent.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM PlexSeasonsContent");
}
if (ombi.PlexServerContent.Any())
{
external.PlexServerContent.AddRange(ombi.PlexServerContent.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM PlexServerContent");
}
if (ombi.EmbyEpisode.Any())
{
external.EmbyEpisode.AddRange(ombi.EmbyEpisode.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyEpisode");
}
if (ombi.EmbyContent.Any())
{
external.EmbyContent.AddRange(ombi.EmbyContent.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyContent");
}
if (ombi.RadarrCache.Any())
{
external.RadarrCache.AddRange(ombi.RadarrCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM RadarrCache");
}
if (ombi.SonarrCache.Any())
{
external.SonarrCache.AddRange(ombi.SonarrCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM SonarrCache");
}
if (ombi.LidarrAlbumCache.Any())
{
external.LidarrAlbumCache.AddRange(ombi.LidarrAlbumCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrAlbumCache");
}
if (ombi.LidarrArtistCache.Any())
{
external.LidarrArtistCache.AddRange(ombi.LidarrArtistCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrArtistCache");
}
if (ombi.SickRageEpisodeCache.Any())
{
external.SickRageEpisodeCache.AddRange(ombi.SickRageEpisodeCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageEpisodeCache");
}
if (ombi.SickRageCache.Any())
{
external.SickRageCache.AddRange(ombi.SickRageCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageCache");
}
if (ombi.CouchPotatoCache.Any())
{
external.CouchPotatoCache.AddRange(ombi.CouchPotatoCache.ToList());
ombi.Database.ExecuteSqlCommand("DELETE FROM CouchPotatoCache");
}
external.SaveChanges();
tran.Commit();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
///// <summary>
///// This is to remove the Settings from the Ombi.db to the "new"
///// OmbiSettings.db
/////
///// Ombi is hitting a limitation with SQLite where there is a lot of database activity
///// and SQLite does not handle concurrency at all, causing db locks.
/////
///// Splitting it all out into it's own DB helps with this.
///// </summary>
//private static void CheckAndMigrate()
//{
// var doneGlobal = false;
// var doneConfig = false;
// var ombi = new OmbiContext();
// var settings = new SettingsContext();
// try
// {
// using (var tran = settings.Database.BeginTransaction())
// {
// if (ombi.Settings.Any() && !settings.Settings.Any())
// {
// // OK migrate it!
// var allSettings = ombi.Settings.ToList();
// settings.Settings.AddRange(allSettings);
// doneGlobal = true;
// }
// // Check for any application settings
// if (ombi.ApplicationConfigurations.Any() && !settings.ApplicationConfigurations.Any())
// {
// // OK migrate it!
// var allSettings = ombi.ApplicationConfigurations.ToList();
// settings.ApplicationConfigurations.AddRange(allSettings);
// doneConfig = true;
// }
// settings.SaveChanges();
// tran.Commit();
// }
// }
// catch (Exception e)
// {
// Console.WriteLine(e);
// throw;
// }
// using (var tran = ombi.Database.BeginTransaction())
// {
// // Now delete the old stuff
// if (doneGlobal)
// ombi.Database.ExecuteSqlCommand("DELETE FROM GlobalSettings");
// if (doneConfig)
// ombi.Database.ExecuteSqlCommand("DELETE FROM ApplicationConfiguration");
// tran.Commit();
// }
// // Now migrate all the external stuff
// var external = new ExternalContext();
// try
// {
// using (var tran = external.Database.BeginTransaction())
// {
// if (ombi.PlexEpisode.Any())
// {
// external.PlexEpisode.AddRange(ombi.PlexEpisode.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM PlexEpisode");
// }
// if (ombi.PlexSeasonsContent.Any())
// {
// external.PlexSeasonsContent.AddRange(ombi.PlexSeasonsContent.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM PlexSeasonsContent");
// }
// if (ombi.PlexServerContent.Any())
// {
// external.PlexServerContent.AddRange(ombi.PlexServerContent.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM PlexServerContent");
// }
// if (ombi.EmbyEpisode.Any())
// {
// external.EmbyEpisode.AddRange(ombi.EmbyEpisode.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyEpisode");
// }
// if (ombi.EmbyContent.Any())
// {
// external.EmbyContent.AddRange(ombi.EmbyContent.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM EmbyContent");
// }
// if (ombi.RadarrCache.Any())
// {
// external.RadarrCache.AddRange(ombi.RadarrCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM RadarrCache");
// }
// if (ombi.SonarrCache.Any())
// {
// external.SonarrCache.AddRange(ombi.SonarrCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM SonarrCache");
// }
// if (ombi.LidarrAlbumCache.Any())
// {
// external.LidarrAlbumCache.AddRange(ombi.LidarrAlbumCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrAlbumCache");
// }
// if (ombi.LidarrArtistCache.Any())
// {
// external.LidarrArtistCache.AddRange(ombi.LidarrArtistCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM LidarrArtistCache");
// }
// if (ombi.SickRageEpisodeCache.Any())
// {
// external.SickRageEpisodeCache.AddRange(ombi.SickRageEpisodeCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageEpisodeCache");
// }
// if (ombi.SickRageCache.Any())
// {
// external.SickRageCache.AddRange(ombi.SickRageCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM SickRageCache");
// }
// if (ombi.CouchPotatoCache.Any())
// {
// external.CouchPotatoCache.AddRange(ombi.CouchPotatoCache.ToList());
// ombi.Database.ExecuteSqlCommand("DELETE FROM CouchPotatoCache");
// }
// external.SaveChanges();
// tran.Commit();
// }
// }
// catch (Exception e)
// {
// Console.WriteLine(e);
// throw;
// }
//}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)

@ -73,7 +73,7 @@ namespace Ombi
options.User.AllowedUserNameCharacters = string.Empty;
});
services.ConfigureDatabases();
services.AddHealthChecks();
services.AddMemoryCache();
@ -122,7 +122,7 @@ namespace Ombi
app.UseQuartz().GetAwaiter().GetResult();
var ctx = serviceProvider.GetService<IOmbiContext>();
var ctx = serviceProvider.GetService<OmbiContext>();
loggerFactory.AddSerilog();
app.UseHealthChecks("/health");

Loading…
Cancel
Save