/// <summary> /// Saves the specified egm metrics. /// </summary> /// <param name="egmMetrics">The egm metrics.</param> public void Save(ICollection <EgmMetric> egmMetrics) { using (var context = new HmsDbContext()) { //context.Database.Log = Console.Write; foreach (var egmMetric in egmMetrics) { if (!context.EgmMetrics.Any(metric => metric.Id == egmMetric.Id)) { // no matching PK for this EgmMetric in database, // thus we create new entity and add it to db DaoUtilities.SaveCreatedEntity(context, context.EgmMetrics, egmMetric, SetNewEntityState, false); } else { // matching PK found, thus we update state of existing EgmMetric entity DaoUtilities.SaveUpdatedEntity(context, context.EgmMetrics, egmMetric, UpdateExistingEntityState, false); } } DaoUtilities.SaveToDbWithRetry(context, DaoUtilities.SaveType.UpdateExistingEntity, ResolveEntityUpdateConflict); } }
/// <summary> /// Saves the specified composite egm meter datas. /// </summary> /// <param name="compositeEgmMeterDatas">The composite egm meter datas.</param> public void Save(ICollection <CompositeEgmMeterData> compositeEgmMeterDatas) { using (var context = new HmsDbContext()) { //context.Database.Log = Console.Write; foreach (var compositeEgmMeterData in compositeEgmMeterDatas) { if (!context.CompositeEgmMeterDatas.Any(cemd => cemd.Id == compositeEgmMeterData.Id)) { // no matching PK for this CompositeEgmMeterData in database, // thus we create new entity and add it to db DaoUtilities.SaveCreatedEntity(context, context.CompositeEgmMeterDatas, compositeEgmMeterData, SetNewEntityState, false); } else { // matching PK found, thus we update state of existing CompositeEgmMeterData entity DaoUtilities.SaveUpdatedEntity(context, context.CompositeEgmMeterDatas, compositeEgmMeterData, UpdateExistingEntityState, false); } } DaoUtilities.SaveToDbWithRetry(context, DaoUtilities.SaveType.UpdateExistingEntity, ResolveEntityUpdateConflict); } }
/// <summary> /// Cleans EgmMetric Entities older than specified date-time. /// </summary> /// <param name="oldDateTime">The old date time.</param> public void CleanOlderThan(DateTime oldDateTime) { using (var context = new HmsDbContext()) { context.EgmMetrics.RemoveRange( context.EgmMetrics.Where( mr => mr.ReportedAt != DaoUtilities.UnsentData && mr.ReportedAt < oldDateTime)); DaoUtilities.SaveToDbWithRetry(context, DaoUtilities.SaveType.DeleteExistingEntity, ResolveEntityUpdateConflict); } }
/// <summary> /// Deletes the specified composite egm meter data. /// </summary> /// <param name="compositeEgmMeterData">The composite egm meter data.</param> public void Delete(CompositeEgmMeterData compositeEgmMeterData) { using (var context = new HmsDbContext()) { if (!context.CompositeEgmMeterDatas.Any(cemd => cemd.Id == compositeEgmMeterData.Id)) { return; } // matching PK found, thus we proceed with Delete DaoUtilities.DeleteEntity(context, context.CompositeEgmMeterDatas, compositeEgmMeterData); } }
/// <summary> /// Deletes the specified EgmMetric entity. /// </summary> /// <param name="egmMetric">The EgmMetric entity to delete.</param> public void Delete(EgmMetric egmMetric) { using (var context = new HmsDbContext()) { if (!context.EgmMetrics.Any(mr => mr.Id == egmMetric.Id)) { return; } // matching PK found, thus we proceed with Delete DaoUtilities.DeleteEntity(context, context.EgmMetrics, egmMetric); } }
/// <summary> /// Deletes the specified EgmVersion entity. /// </summary> /// <param name="egmVersion">The EgmVersion entity to delete.</param> public void Delete(EgmVersion egmVersion) { using (var context = new HmsDbContext()) { if (!context.EgmVersions.Any(v => v.Id == egmVersion.Id)) { return; } // matching PK found, thus we proceed with Delete DaoUtilities.DeleteEntity(context, context.EgmVersions, egmVersion); } }
/// <summary> /// Deletes the specified egm windows event entity. /// </summary> /// <param name="egmWindowsEvent">The egm windows event entity.</param> public void Delete(EgmWindowsEvent egmWindowsEvent) { using (var context = new HmsDbContext()) { if (!context.EgmWindowsEvents.Any(winEvt => winEvt.Id == egmWindowsEvent.Id)) { return; } // matching PK found, thus we proceed with Delete DaoUtilities.DeleteEntity(context, context.EgmWindowsEvents, egmWindowsEvent); } }
/// <summary> /// Updates the state of the existing entity. /// </summary> /// <param name="context">The context.</param> /// <param name="entityEntry">The entity entry.</param> /// <param name="egmMetric">The egm metric.</param> private static void UpdateExistingEntityState(HmsDbContext context, DbEntityEntry entityEntry, EgmMetric egmMetric) { var metricEntity = (EgmMetric)entityEntry.Entity; if (!metricEntity.SentAt.Equals(egmMetric.SentAt)) { metricEntity.SentAt = egmMetric.SentAt; } if (!metricEntity.ReportGuid.Equals(egmMetric.ReportGuid)) { metricEntity.ReportGuid = egmMetric.ReportGuid; } DaoUtilities.UpdateVersion(context, entityEntry); }
/// <summary> /// Updates the state of the existing entity. /// </summary> /// <param name="context">The context.</param> /// <param name="entityEntry">The entity entry.</param> /// <param name="egmWindowsEvent">The egm windows event entity.</param> private static void UpdateExistingEntityState(HmsDbContext context, DbEntityEntry entityEntry, EgmWindowsEvent egmWindowsEvent) { var winEvtEntity = (EgmWindowsEvent)entityEntry.Entity; if (!winEvtEntity.SentAt.Equals(egmWindowsEvent.SentAt)) { winEvtEntity.SentAt = egmWindowsEvent.SentAt; } if (!winEvtEntity.ReportGuid.Equals(egmWindowsEvent.ReportGuid)) { winEvtEntity.ReportGuid = egmWindowsEvent.ReportGuid; } DaoUtilities.UpdateVersion(context, entityEntry); }
/// <summary> /// Resolves the entity update conflict. /// </summary> /// <param name="context">The context.</param> /// <param name="entityEntry">The entity entry.</param> private static void ResolveEntityUpdateConflict(HmsDbContext context, DbEntityEntry entityEntry) { /////////////////////////////////////////////////////////////////////////// // This should never occur for EgmMetric entities // because we simply add records to the db table when we receive // them from the HMS EGM Client message (HMS Onsite Service) or the HMS Onsite // Service (HMS Cloud Service). We do update the records on the // HMS Onsite Service when we package them up and send them to // the HMS Cloud Service (ReportGuid and SentAt fields are updated) // but in a single-threaded way and only after having created the // initial record. // // We will use the "first in wins" resolution approach, but this ought // never be invoked. ////////////////////////////////////////////////////////////////////////// entityEntry.Reload(); DaoUtilities.UpdateVersion(context, entityEntry); }
/// <summary> /// Saves the specified EgmMetric. /// </summary> /// <param name="egmMetric">The EgmMetric to save.</param> public void Save(EgmMetric egmMetric) { using (var context = new HmsDbContext()) { //context.Database.Log = Console.Write; if (!context.EgmMetrics.Any(metric => metric.Id == egmMetric.Id)) { // no matching PK for this EgmMetric in database, // thus we create new entity and add it to db DaoUtilities.SaveCreatedEntity(context, context.EgmMetrics, egmMetric, SetNewEntityState); } else { // matching PK found, thus we update state of existing EgmMetric entity DaoUtilities.SaveUpdatedEntity(context, context.EgmMetrics, egmMetric, UpdateExistingEntityState); } } }
/// <summary> /// Saves the specified composite EGM meter data. /// </summary> /// <param name="compositeEgmMeterData">The composite EGM meter data.</param> public void Save(CompositeEgmMeterData compositeEgmMeterData) { using (var context = new HmsDbContext()) { //context.Database.Log = Console.Write; if (!context.CompositeEgmMeterDatas.Any(cemd => cemd.Id == compositeEgmMeterData.Id)) { // no matching PK for this CompositeEgmMeterData in database, // thus we create new entity and add it to db DaoUtilities.SaveCreatedEntity(context, context.CompositeEgmMeterDatas, compositeEgmMeterData, SetNewEntityState); } else { // matching PK found, thus we update state of existing CompositeEgmMeterData entity DaoUtilities.SaveUpdatedEntity(context, context.CompositeEgmMeterDatas, compositeEgmMeterData, UpdateExistingEntityState); } } }
/// <summary> /// Resolves the entity update conflict. /// </summary> /// <param name="context">The context.</param> /// <param name="entityEntry">The entity entry.</param> private static void ResolveEntityUpdateConflict(HmsDbContext context, DbEntityEntry entityEntry) { /////////////////////////////////////////////////////////////////////////// // There is potential for DbConcurrencyUpdate optimistic locking conflicts // with CompositeEgmMeterData entities. // // Specifically, when multiple threads are consuming incoming meter reading // data on the HMS Cloud Service, there is the potential for more than one // such thread to have meter readings with the same EgmCompositeKey. // // Thus, we need to sort out such potential conflicts here. ////////////////////////////////////////////////////////////////////////// var currentValues = entityEntry.CurrentValues; var originalValues = entityEntry.OriginalValues; entityEntry.Reload(); var dbValues = entityEntry.CurrentValues; var currentUpdates = new List <string>(); var dbUpdates = new List <string>(); var mutableMeters = new List <string> { nameof(CompositeEgmMeterData.CoinIn), nameof(CompositeEgmMeterData.CoinOut), nameof(CompositeEgmMeterData.BillDrop), nameof(CompositeEgmMeterData.GamesPlayed), nameof(CompositeEgmMeterData.GamesLost), nameof(CompositeEgmMeterData.GamesWon), nameof(CompositeEgmMeterData.Handpay), nameof(CompositeEgmMeterData.Jackpot), nameof(CompositeEgmMeterData.MeteredAttendantPaidProgressive), nameof(CompositeEgmMeterData.MeteredMachinePaidProgressive), nameof(CompositeEgmMeterData.TicketDrop), nameof(CompositeEgmMeterData.TicketOut) }; // Look for updates to meters (relative to original values) in both // current changes and conflicting db updates foreach (var meter in mutableMeters) { if (currentValues.GetValue <long>(meter) != originalValues.GetValue <long>(meter)) { currentUpdates.Add(meter); } if (dbValues.GetValue <long>(meter) != originalValues.GetValue <long>(meter)) { dbUpdates.Add(meter); } } // Check if there are meters which were updated in both our current updates // and the conflicting db updates. foreach (var commonMeter in currentUpdates.Intersect(dbUpdates)) { // since the mutable meters can only increase in value, // we take the larger value as winner var currentMeterValue = currentValues.GetValue <long>(commonMeter); var dbMeterValue = dbValues.GetValue <long>(commonMeter); entityEntry.CurrentValues[commonMeter] = currentMeterValue > dbMeterValue ? currentMeterValue : dbMeterValue; currentUpdates.Remove(commonMeter); dbUpdates.Remove(commonMeter); } // Take any current updates and apply to entity foreach (var meter in currentUpdates) { entityEntry.CurrentValues[meter] = currentValues.GetValue <long>(meter); } // Finally, we update the dependent meters (SlotRevenue and AverageBet) var coinIn = entityEntry.CurrentValues.GetValue <long>(nameof(CompositeEgmMeterData.CoinIn)); var coinOut = entityEntry.CurrentValues.GetValue <long>(nameof(CompositeEgmMeterData.CoinOut)); var gamesPlayed = entityEntry.CurrentValues.GetValue <long>(nameof(CompositeEgmMeterData.GamesPlayed)); var jackpot = entityEntry.CurrentValues.GetValue <long>(nameof(CompositeEgmMeterData.Jackpot)); if (CompositeEgmMeterData.MeterNotRecordedL != coinIn && CompositeEgmMeterData.MeterNotRecordedL != gamesPlayed && 0 < gamesPlayed) { entityEntry.CurrentValues[nameof(CompositeEgmMeterData.AverageBet)] = (decimal)coinIn / gamesPlayed; } if (CompositeEgmMeterData.MeterNotRecordedL != coinIn && CompositeEgmMeterData.MeterNotRecordedL != coinOut && CompositeEgmMeterData.MeterNotRecordedL != jackpot) { entityEntry.CurrentValues[nameof(CompositeEgmMeterData.SlotRevenue)] = coinIn - coinOut - jackpot; } DaoUtilities.UpdateVersion(context, entityEntry); }
/// <summary> /// Updates the state of the existing entity. /// </summary> /// <param name="context">The context.</param> /// <param name="entityEntry">The entity entry.</param> /// <param name="compositeEgmMeterData">The composite egm meter data.</param> private static void UpdateExistingEntityState(HmsDbContext context, DbEntityEntry entityEntry, ICompositeEgmMeterData compositeEgmMeterData) { entityEntry.CurrentValues.SetValues(compositeEgmMeterData); DaoUtilities.UpdateVersion(context, entityEntry); }