using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; using Disco.Data.Repository; using Disco.Models.Repository; namespace Disco.BI { public static class DeviceModelBI { // Added: 2013-02-07 G# // Ensure Duplicate Device Models are not created by creating only one Device Model at a time // http://www.discoict.com.au/forum/support/2013/2/duplicate-device-models.aspx // Thanks to Michael Vorster for reporting this problem. private static object _CreateDeviceModelLock = new object(); public static Tuple GetOrCreateDeviceModel(this DbSet DeviceModelsSet, string Manufacturer, string Model, string ModelType) { // Already Exists? var deviceModel = DeviceModelsSet.FirstOrDefault(dm => dm.Manufacturer == Manufacturer && dm.Model == Model); if (deviceModel == null) { // Ensure only one thread/request at a time lock (_CreateDeviceModelLock) { // Check again now that lock is enforced deviceModel = DeviceModelsSet.FirstOrDefault(dm => dm.Manufacturer == Manufacturer && dm.Model == Model); if (deviceModel == null) { // Create the Device Model in a different DataContext so we don't have to commit unrelated changes using (DiscoDataContext dbContext = new DiscoDataContext()) { var addDeviceModel = new DeviceModel { Manufacturer = Manufacturer, Model = Model, ModelType = ModelType, Description = string.Format("{0} {1}", Manufacturer, Model) }; dbContext.DeviceModels.Add(addDeviceModel); dbContext.SaveChanges(); } // Obtain the Device Model with the in-scope DataContext // - Overhead acknowledged, but reasonable given the infrequency of occurrence deviceModel = DeviceModelsSet.FirstOrDefault(dm => dm.Manufacturer == Manufacturer && dm.Model == Model); return new Tuple(deviceModel, true); } } } return new Tuple(deviceModel, false); } // Added: 2013-02-07 G# } }