using DataPROWin7.DataModel; using DTS.Common.Import.Enums; using DTS.Common.ISO; using System; using System.Collections.Generic; using System.Linq; namespace DTS.Common.Import.Persist { public class SaveCustomChannels : SaveVariantBase { public ISO13499FileDb IsoDb { get; set; } public Dictionary CustomChannelTextIdToOldChannelId { get; set; } = new Dictionary(); public Dictionary CustomChannelOldChannelIdToChannel { get; set; } = new Dictionary(); public SaveCustomChannels(ImportObject importObject, IPersistCalculator persistCalculator, IImportNotification importNotification, Func isCancelled = null) : base(importObject, persistCalculator, importNotification, isCancelled) { } public override void Save() { //there's a bit of a dance here //when we commit embedded non iso groups for a non iso test setup for instance, the custom channels for that test setup are destroyed and //recreated new, and as they were before they shall be again, but we'd like to link our level triggers we are importing that have the old ids //to the new ids that will exist //since we will go through all the custom channels in the code below, it's a good point to make a note of what once was //then later on after we commit the groups in question, we'll make a note of what now is, and then correct it in all test setups. //custom channels have an autoincrement id, because of this we have to do a two step dance with them //#1, look for existing custom channel if possible and just use it's id //#2, or insert a new custom channel, get it's id, then update all templates and channels with that custom channel // with th enew id var customChannels = _importObject.CustomChannels().ToList(); if (customChannels == null || !customChannels.Any()) { return; } for (int currentCCIdx = customChannels.Count - 1; currentCCIdx >= 0; currentCCIdx--) { var cc = customChannels[currentCCIdx]; customChannels.RemoveAt(currentCCIdx); if (IsCancelled()) { return; } var oldid = cc.Id; //this is the id from the import file long newid; var existing = CustomChannelList.List.GetChannelByISOCode(IsoCodeStatics.GetString(cc, false), false); if (null != existing) { //custom channel already exists, just use it's id newid = existing.Channel.Id; cc.SetId(newid); } else { //custom channel doesn't exist, we need to insert it, but we have to clear the id first so we can insert it //we've already held onto the old id, so we're good. cc.ClearId(); } //update or insert the custom channel var customchannel = new CustomChannel(cc); CustomChannelList.List.Commit(customchannel, true, false); newid = customchannel.Channel.Id; //this is now the official id of the custom channel, //go through all the channels, updating the ids if needed var groupTemplates = _importObject.GroupTemplates().ToList(); for (var i = groupTemplates.Count - 1; i >= 0; i--) { var gt = groupTemplates[i]; var isoGT = gt.ToISOTestObjectTemplate(); var bUpdated = false; foreach (var ch in isoGT.Channels) { if (ch.Channel.Text_L1 != cc.Text_L1 || ch.Channel.MMEChannelType != (int)MMEPossibleChannels.MMEChannelTypes.SQL) continue; ch.SetID(newid); bUpdated = true; } //if the group template wasn't updated, then we are done with that group template, if however it was updated //we then have to go through all groups and update the sensor assignments if (!bUpdated) continue; var db = IsoDb; groupTemplates[i] = new DataPROWin7.DataModel.TestObjectTemplate(isoGT, ref db); var templateName = isoGT.TemplateName; _importNotification.SetStatus.Invoke(new ImportStatus { ExtraStatus = ImportExtraStatus.ReadingGroups, PossibleStatus = PossibleStatus.Importing }); var groups = new List(_importObject.Groups()); foreach (var t in _importObject.TestSetups().Where(t => t.AddedGroups.Any())) { groups.AddRange(t.AddedGroups.ToArray()); } foreach (var g in groups) { if (g.Template.TemplateName != templateName) continue; var oldISOTO = g.GetISOTestObject(); //because of the changing custom channel ids, we have to hold onto some of the properties //of the import group before we repopulate it with the new template var isoCodeToSensorSerialNumberLookup = new Dictionary(); var isoCodeToHardwareChannelIdLookup = new Dictionary(); foreach (var ch in oldISOTO.AllChannels) { if (ch.Channel.Text_L1 != cc.Text_L1) continue; if (string.IsNullOrWhiteSpace(ch.SensorSerialNumber)) continue; isoCodeToSensorSerialNumberLookup[IsoCodeStatics.GetString(ch.Channel, false)] = ch.SensorSerialNumber; isoCodeToHardwareChannelIdLookup[IsoCodeStatics.GetString(ch.Channel, false)] = ch.HardwareId; } //assign the new template, and then update the channels in the template with a sensor/hardware id if necessary g.SetTemplateDontResetISOObject(groupTemplates[i]); var newISOTO = g.GetISOTestObject(); foreach (var ch in newISOTO.AllChannels) { if (ch.Channel.MMEChannelType == (int)MMEPossibleChannels.MMEChannelTypes.ISO13499_106) { continue; } var ccIso = IsoCodeStatics.GetString(cc, false); if (ch.Channel.Text_L1 != cc.Text_L1 || !isoCodeToSensorSerialNumberLookup.ContainsKey(ccIso)) continue; //keep a track of what once was var oldChannelId = ch.GetIdWithSpecificChannelId(oldid); CustomChannelTextIdToOldChannelId[ccIso] = oldChannelId; CustomChannelOldChannelIdToChannel[oldChannelId] = ch; ch.Channel.SetId(customchannel.Channel.Id); ch.SensorSerialNumber = isoCodeToSensorSerialNumberLookup[ccIso]; ch.HardwareId = isoCodeToHardwareChannelIdLookup[ccIso]; } } } _persistCalculator.AddDone(); _importNotification.SetProgress(_persistCalculator.ProgressValue); //speed up memory collection by forcing GC //11287 Out of memory exception when importing large CSV Test Setup files //This is a critical code smell- moved from existing code base find a better way to handle this in future //https://rules.sonarsource.com/csharp/RSPEC-1215/ // GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); } CustomChannelList.List.UpdateAll(); } } }