using System; using System.Collections.Generic; using FluentNHibernate.Cfg; using FluentNHibernate.Cfg.Db; using NHibernate; using NHibernate.Cfg; using NHibernate.Tool.hbm2ddl; using log4net; using TracingDB.Entities; namespace TracingDB { public static class DB { static readonly ILog log = LogManager.GetLogger(typeof(DB)); /// /// Current session factory for the last used connection string or null /// public static ISessionFactory SessionFactory; public static ISession Session; /// 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 } } } /// /// 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') /// /// A database session public static ISessionFactory CreateSessionFactory(bool createDB) { FluentConfiguration cfg = Fluently .Configure() .Database(MySQLConfiguration.Standard.ConnectionString(connectionString)) .Mappings(m => m.FluentMappings.AddFromAssemblyOf()); if (createDB) { return cfg.ExposeConfiguration(BuildSchemaCreate).BuildSessionFactory(); } else { return cfg.ExposeConfiguration(BuildSchema).BuildSessionFactory(); } } public delegate void BuildSchemaDlgt(Configuration config); public static void BuildSchema(Configuration config) { /// This NHibernate tool takes a configuration (with mapping info in) /// and exports a database schema from it new SchemaExport(config).SetOutputFile("db_schema"); } static void BuildSchemaCreate(Configuration config) { /// This NHibernate tool takes a configuration (with mapping info in) /// and exports a database schema from it new SchemaExport(config).Create(true, true); } /// Create a NHibernate session for the given database public static ISession CreateSession(string connectionString) { ConnectionString = connectionString; /// Clears session factory on connction string change if (SessionFactory == null) SessionFactory = CreateSessionFactory(); return SessionFactory.OpenSession(); } /// /// Create an empty 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(string connectionString) { ConnectionString = connectionString; ISessionFactory sessionFactory = CreateSessionFactory(true); if (sessionFactory == null) return false; /// Populate the database using (var session = sessionFactory.OpenSession()) { //using (var transaction = session.BeginTransaction()) //{ // var part1 = new Part("flow tube", CodeType.UniqueNr, CodeForm.QRCode, 0); // session.SaveOrUpdate(part1); // transaction.Commit(); //} } return true; } /// /// Save a reference record and related records into the database. /// /// DB session /// Referece record public static void SaveRecords(ISession session, ReferenceRecord refRecord) { log.Info("Saving data to MySQL database"); session.SaveOrUpdate(refRecord); log.InfoFormat(" ReferenceRecord : {0}", refRecord); foreach (var r in refRecord.Records) { session.SaveOrUpdate(r); log.InfoFormat(" Record : {0}", r); } } /// /// Delete a reference record and related records from the database. /// /// DB session /// Reference record public static void DeleteRecords(ISession session, ReferenceRecord refRecord) { log.Info("Deleting data from MySQL database"); foreach (var r in refRecord.Records) { session.Delete(r); log.InfoFormat(" Record : {0}", r); } session.Delete(refRecord); log.InfoFormat(" ReferenceRecord : {0}", refRecord); } /// /// Get process of the last record with the reference part code equal to 'pcbNumber' /// /// DB session /// PCB number (code) /// Process public static Process GetProcess(ISession session, string pcbNumber) { if (string.IsNullOrEmpty(pcbNumber)) return null; try { /// Read all already existing reference records with Code==pcbNumber, referenceRecords[0] will be the most recent one var referenceRecords = session.QueryOver() .Where(rr => (rr.Code == pcbNumber && rr.Result == 0)) .OrderBy(rr => rr.TimeStamp).Desc .List(); if (referenceRecords.Count == 0) return null; /// Returns an empty list if no such ref. record found return referenceRecords[0].Process; } catch { return null; } } /// /// Updates processes, processDictionary and workstepsDictionary /// /// DB session public static IList ReadWorkflowsFromDB(ISession session, string thisWorkstepName, out Dictionary workflowDict, out Dictionary> workflowStepsDict, out Dictionary verifInfos, bool readDeactivatedWorkflows = false) { IList workflows; if (readDeactivatedWorkflows) { workflows = session.QueryOver().Where(pr => ((pr.ReleaseStatus == ReleaseStatus.Released) || (pr.ReleaseStatus == ReleaseStatus.ReleasedActive) || (pr.ReleaseStatus == ReleaseStatus.ToBeApproved) || (pr.ReleaseStatus == ReleaseStatus.Deactivated) )).List(); } else { workflows = session.QueryOver().Where(pr => ((pr.ReleaseStatus == ReleaseStatus.Released) || (pr.ReleaseStatus == ReleaseStatus.ReleasedActive) || (pr.ReleaseStatus == ReleaseStatus.ToBeApproved) )).List(); } workflowDict = new Dictionary(); workflowStepsDict = new Dictionary>(); verifInfos = new Dictionary(); foreach (var wf in workflows) { IList steps = session.QueryOver() .Where(ws => ((ws.Process == wf) && (ws.Name == thisWorkstepName))) .List(); workflowDict.Add(wf.Id, wf); workflowStepsDict.Add(wf.Id, steps); Workstep step; bool verifyRefPart; Part verifiedPart; if (steps.Count == 1 && TracingDB.DB.AnalyzeProcess(session, wf, steps[0], out step, out verifyRefPart, out verifiedPart)) { verifInfos.Add(wf.Id, new ScanVerificationInfo(step, verifyRefPart, verifiedPart)); log.WarnFormat("Workflow {0} :: Verified step={1} part={2} verify ref. part={3}", wf, step, verifiedPart, verifyRefPart); } } return workflows; } /// /// Finds a workstep and a part to be verified (typically a previous workstep and one of its parts). /// Updates this.verifiedWorkstep, this.verifiedPart and this.verifyReferencePart. /// Returns false if there is no workstep or part to be verified. /// /// MySQL DB session /// Process to be analyzed /// Workstep to be analyzed /// true if there is a verified workstep and part public static bool AnalyzeProcess(ISession dbSession, Process process, Workstep workstep, out Workstep verifiedWorkstep, out bool verifyReferencePart, out Part verifiedPart) { verifiedWorkstep = null; /// Disable any verification verifyReferencePart = true; verifiedPart = null; if (process == null || workstep == null) return false; try { if (workstep.ReferencePart != null) { IList worksteps = dbSession.QueryOver() .Where(x => (x.Process == process)) .Where(x => (x.WorkstepNr < workstep.WorkstepNr)) .OrderBy(x => x.WorkstepNr).Asc .List(); for (int i = worksteps.Count - 1; i >= 0; i--) { if (worksteps[i].ReferencePart != null) { if (worksteps[i].ReferencePart.Id == workstep.ReferencePart.Id) { /// Enable checking reference part verifiedWorkstep = worksteps[i]; verifiedPart = workstep.ReferencePart; verifyReferencePart = true; return true; } foreach (var thisStepPart in workstep.Parts) { if (worksteps[i].ReferencePart.Id == thisStepPart.Id) { verifiedWorkstep = worksteps[i]; verifiedPart = worksteps[i].ReferencePart; verifyReferencePart = true; return true; } } } foreach (var part in worksteps[i].Parts) { bool isUnique = (part.CodeLocation == CodeLocation.OnPart) && ((part.CodeType == CodeType.UniqueNr) || (part.CodeType == CodeType.FlowtubeNr) || (part.CodeType == CodeType.FlowtubeNrLU)); if (isUnique) { if (part.Id == workstep.ReferencePart.Id) { /// Enable checking reference part verifiedWorkstep = worksteps[i]; verifiedPart = part; verifyReferencePart = false; log.ErrorFormat("AnalyzeProcess(session , {0}, {1}) returned 'true' : verWorkstep = {2}, verPart = {3}, verRefPart = {4}", process.Name, workstep.Name); return true; } foreach (var thisStepPart in workstep.Parts) { if (part.Id == thisStepPart.Id) { verifiedWorkstep = worksteps[i]; verifiedPart = part; verifyReferencePart = false; return true; } } } } } } log.ErrorFormat("AnalyzeProcess(session , {0}, {1}) returned 'false'", process.Name, workstep.Name); return false; } catch (Exception exc) { log.ErrorFormat("AnalyzeProcess(session , {0}, {1}) failed : {2}", process.Name, workstep.Name, exc.Message); return false; } } /// /// Obsolete, use WorkplaceRegistration class instead /// public static bool RegisterWorkplace(ISession session, string workplace, string user, string ipAddress, string processName, string workstepName, DateTime valiUntil) { try { IList wpRegs = session .QueryOver() .Where(x => (x.Workplace == workplace)) .List(); if (wpRegs.Count == 0) { WorkplaceRegistration wpReg = new WorkplaceRegistration(workplace, user, ipAddress, processName, workstepName); wpRegs.Add(wpReg); session.SaveOrUpdate(wpReg); log.InfoFormat("RegisterWorkplace(., {0}, {1}, ...) successful (new)", workplace, user); return true; } else if (wpRegs.Count == 1) { WorkplaceRegistration wpReg = wpRegs[0]; wpReg.Active = true; wpReg.TimeStamp = DateTime.Now; wpReg.ValidUntil = valiUntil; wpReg.UserName = user; wpReg.IPAddress = ipAddress; wpReg.ProcessName = processName; wpReg.WorkstepName = workstepName; session.SaveOrUpdate(wpReg); log.InfoFormat("RegisterWorkplace(., {0}, {1}, ...) successful", workplace, user); return true; } else { log.ErrorFormat("RegisterWorkplace(., {0}, {1}, ...) failed", workplace, user); return false; } } catch (Exception e) { log.ErrorFormat("RegisterWorkplace(., {0}, {1}, ...) exception: {2}", workplace, user, e.Message); return false; } } /// /// Obsolete, use WorkplaceRegistration class instead /// public static bool UnregisterWorkplaceObsolete(ISession session, string workplace) { try { IList wpRegs = session.QueryOver() .Where(x => (x.Workplace == workplace)) .List(); if (wpRegs.Count == 1) { WorkplaceRegistration wpReg = wpRegs[0]; wpReg.Active = false; wpReg.TimeStamp = DateTime.Now; session.SaveOrUpdate(wpReg); log.InfoFormat("UnregisterWorkplace(., {0}) successful", workplace); return true; } else { log.ErrorFormat("UnregisterWorkplace(., {0}) failed", workplace); return false; } } catch (Exception e) { log.ErrorFormat("UnregisterWorkplace(., {0}) exception: {1}", workplace, e.Message); return false; } } } }