///
/// Copyright (c) 2013-2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using log4net;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using Common;
using Results.Entities;
namespace Results
{
public static class DB
{
static readonly ILog log = LogManager.GetLogger(typeof(DB));
/// Session factory for all regular sessions, not for CreateEmptyResultsDB().
public static ISessionFactory SessionFactory;
/// Connection string for all sessions
static string connectionString;
///
public static string ConnectionString
{
get { return connectionString; }
set
{
if (value != connectionString)
{
connectionString = value;
SessionFactory = null; /// Clear SessionFactory on connection string change
}
}
}
/// Database type (MySQL or SQLite) for all sessions
private static Common.DBType dbType;
///
public static Common.DBType DbType
{
get { return dbType; }
set { dbType = value; SessionFactory = null; }
}
///
/// NHibernate session factory (to create the database session 'SessionFactory')
///
/// A database session
static ISessionFactory CreateSessionFactory()
{
return CreateSessionFactory(false);
}
///
/// NHibernate session factory (to create the database session 'SessionFactory')
///
/// true = Create a new DB, false = Regular DB
/// A database session
public static ISessionFactory CreateSessionFactory(bool createDB)
{
FluentConfiguration cfg = Fluently.Configure();
switch (dbType)
{
default:
case DBType.MySql:
cfg = cfg.Database(MySQLConfiguration.Standard.ConnectionString(connectionString));
break;
case DBType.SQLite:
cfg = cfg.Database(SQLiteConfiguration.Standard.UsingFile(connectionString));
break;
}
cfg = cfg.Mappings(m => m.FluentMappings.AddFromAssemblyOf());
if (createDB)
{
return cfg.ExposeConfiguration(BuildSchemaCreate).BuildSessionFactory();
}
else
{
return cfg.ExposeConfiguration(BuildSchema).BuildSessionFactory();
}
}
static void BuildSchema(Configuration config)
{
/// This NHibernate tool takes a configuration with mapping info and exports a database schema
new SchemaExport(config).SetOutputFile("db_schema");
}
static void BuildSchemaCreate(Configuration config)
{
/// This NHibernate tool takes a configuration with mapping info and exports a database schema
new SchemaExport(config).Create(true, true);
}
/// Create a NHibernate session for the given database
public static ISession CreateSession()
{
if (string.IsNullOrEmpty(connectionString))
{
throw new Exception("Connection string was not specified");
}
if (SessionFactory == null) SessionFactory = CreateSessionFactory();
return SessionFactory.OpenSession();
}
public static void SaveObject(object obj)
{
SaveObject(CreateSession(), obj);
}
///
public static void SaveObject(ISession session, object obj)
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(obj);
try { transaction.Commit(); }
catch { }
}
}
public static void DeleteObject(object obj)
{
DeleteObject(CreateSession(), obj);
}
///
public static void DeleteObject(ISession session, object obj)
{
using (var transaction = session.BeginTransaction())
{
session.Delete(obj);
transaction.Commit();
}
}
///
/// Create an empty users database.
/// Database contains only the user 'admin' and the control board component 'CB'.
///
/// DBType.SQLite or DBType.MySql
/// Connection string
/// true=success, false=error
public static bool CreateEmptyDB()
{
ISessionFactory sessionFactory = CreateSessionFactory(true);
if (sessionFactory == null) return false;
/// Populate the database
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
transaction.Commit();
}
}
return true;
}
///
/// Shared data
///
public static IList TestDataList;
public static IList ComponentsList;
public static IList WaterMeterDataList;
///
/// Loads shared data from the database
///
/// Throws NHibernate exceptions
public static void LoadSharedData()
{
ISession session = DB.CreateSession();
TestDataList = session.QueryOver().List();
ComponentsList = session.QueryOver().List();
WaterMeterDataList = session.QueryOver().List();
}
///
/// Loads shared data from the database
///
/// Throws NHibernate exceptions
public static int GetMaxSavedBatchNr()
{
ISession session = DB.CreateSession();
IList batches = session.QueryOver().List();
int maxBatchNr = 0;
foreach (var b in batches)
{
if (b.BatchNr > maxBatchNr) maxBatchNr = b.BatchNr;
}
return maxBatchNr;
}
///
/// Update TestData, Components and WaterMeterData fo tests and water meters in batch results
/// with existing data in static lists TestDataList, ComponentsList and WaterMeterDataList.
///
/// Batch results
/// true when any data modiifed
public static bool UpdateBatchData(Entities.Batch batch)
{
ISession session = DB.CreateSession();
if (session == null) return false;
foreach (var tr in batch.TestRslts)
{
/// Search in TestDataList and update test data in the new batch
TestData td = TestData.UpdateList(TestDataList, tr.TestData);
tr.TestData = td;
/// Search in ComponentsList and update components in the new batch
Components cd = Components.UpdateList(ComponentsList, tr.Components);
tr.Components = cd;
}
foreach (var wm in batch.WaterMeters)
{
/// Search in WaterMeterDataList and update water meter data in the new batch
WaterMeterData wmd = WaterMeterData.UpdateList(WaterMeterDataList, wm.WaterMeterData);
wm.WaterMeterData = wmd;
}
return true; /// TODO: Really check for modifications
}
public static bool SaveNewBatch(Entities.Batch batch)
{
ISession session = DB.CreateSession();
if (session == null) return false;
TestDataList = session.QueryOver().List();
ComponentsList = session.QueryOver().List();
WaterMeterDataList = session.QueryOver().List();
UpdateBatchData(batch);
ITransaction transaction = session.BeginTransaction();
if (transaction == null) return false;
try
{
foreach (var td in TestDataList) if (td.Id == 0) session.SaveOrUpdate(td);
foreach (var cd in ComponentsList) if (cd.Id == 0) session.SaveOrUpdate(cd);
foreach (var wd in WaterMeterDataList) if (wd.Id == 0) session.SaveOrUpdate(wd);
log.Debug(batch.ToString(1));
foreach (var tstRslt in batch.TestRslts)
{
log.Debug(tstRslt.ToString(1));
}
session.SaveOrUpdate(batch);
transaction.Commit();
}
catch (Exception exc)
{
transaction.Rollback();
log.FatalFormat("Saving results of batch #{0} into the results DB failed: {1}", batch.BatchNr, exc.Message);
if (exc.InnerException != null && !string.IsNullOrEmpty(exc.InnerException.Message))
{
log.FatalFormat("Inner exception message: {0}", exc.InnerException.Message);
}
return false;
}
session.Flush();
return true;
}
public static Batch LoadBatch(int batchNr)
{
IList batches;
ISession session = DB.CreateSession();
if (session == null) return null;
try
{
TestDataList = session.QueryOver().List();
ComponentsList = session.QueryOver().List();
WaterMeterDataList = session.QueryOver().List();
batches = session.QueryOver()
.Where(x => (x.BatchNr == batchNr))
.List();
foreach (var batch in batches)
{
batch.TestRslts = session.QueryOver()
.Where(x => (x.Batch.Id == batch.Id))
.List();
batch.WaterMeters = session.QueryOver()
.Where(x => (x.Batch.Id == batch.Id))
.List();
}
return (batches.Count > 0) ? batches[0] : null;
}
catch (Exception exc)
{
log.FatalFormat("Cannot load batch #{0}: {1}", batchNr, exc.Message);
return null;
}
}
}
}