在多个任务之间添加依赖关系

时间:2018-02-01 12:14:07

标签: c# entity-framework

我有一堆'收集者'枚举来自各种设备的几个数据(cpu-type,ram等)。 这些收集器每天运行一次,并使用简单的Web服务发布其数据。 然后,这个Web服务会触发一些方法,使用EF将这些数据导入我们的sql-db。

以下是获取数据后的部分:

 var importPayload = JsonConvert.DeserializeObject(payload.ToString(),
            new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto});

        //Load off the payload to another thread to quickly return to the caller.            
        TypeSwitch.On(importPayload)
            .Case((List<IDeviceType> x) =>
            {
                Task.Run(() => { DeviceType.Update(x, sourceName, sourceId, persistInDatabase); });
            })                
            .Case((List<ICpu> x) =>
            {
                Task.Run(() => { Cpu.Update(x, sourceName, sourceId, persistInDatabase); });
            })
            .Case((List<IMemory> x) =>
            {
                Task.Run(() => { Memory.Update(x, sourceName, sourceId, persistInDatabase); });
            })

以下是更新sql-db中数据的部分。

1。设备类型:

public static class DeviceType
{
    private static readonly Logger Log = LogManager.GetCurrentClassLogger();
    private static readonly DateTime Timestamp = DateTime.Now;

    internal static void Update(IReadOnlyCollection<IDeviceType> payload, string sourceName, int sourceId,
        bool persistInDatabase)
    {
        if (payload == null || !payload.Any())
        {
            Log.Error($"Collector '{sourceName}': Payload is 'NULL' or empty. Cannot import payload into CMDB.");
            return;
        }

        using (var context = CMDBEntities.GetCMDBContext(persistInDatabase, sourceName))
        {
            foreach (var item in payload.Where(a => !string.IsNullOrEmpty(a.Name)))
                Update(context, item.HostName, item.Name, sourceId, sourceName);

            context.SaveChanges();
        }
    }

    private static void Update(CMDBEntities context, string hostName, string systemType, int sourceId,
        string sourceName)
    {
        Log.Debug($"Collector '{sourceName}', Item '{hostName}': Lookup item in CMDB...");

        var ci = context.CMDB_ci.FirstOrDefault(
            a => a.name.ToLower().Equals(hostName.ToLower()) &&
                 a.ci_c_status_id == CiStatus.Active && a.delflag == 0);

        if (ci == null)
        {
            Log.Debug($"Collector '{sourceName}', Item '{hostName}': Item was not found in CMDB. Skipping...");
            return;
        }

        var deviceType =
            context.CMDB_ci_c_devicetype.FirstOrDefault(
                a => a.name.ToLower().Equals(systemType.ToLower()));

        if (deviceType != null)
        {
            var sourceDeviceTypeId = deviceType.ci_c_devicetype_id;
            var cmdbDeviceType = ci.CMDB_ci_devicetype ??
                                 (ci.CMDB_ci_devicetype = new CMDB_ci_devicetype());

            var cmdbDeviceTypeId = ci.CMDB_ci_devicetype.ci_c_devicetype_id;

            if (cmdbDeviceTypeId != sourceDeviceTypeId)
            {
                cmdbDeviceType.ci_c_devicetype_id = sourceDeviceTypeId;
                cmdbDeviceType.LastModBy = sourceName;
                cmdbDeviceType.LastModDateTime = Timestamp;

                ci.LastModBy = sourceName;
                ci.LastModDateTime = Timestamp;
                Log.Debug(
                    $"Collector '{sourceName}', CI '{ci.name}': Device-Type has changed.");
            }
        }
    }
 }

2。 CPU:

 public static class Cpu
 {
     private static readonly Logger Log = LogManager.GetCurrentClassLogger();
     private static readonly DateTime Timestamp = DateTime.Now;

     internal static void Update(IReadOnlyCollection<ICpu> payload, string sourceName, int sourceId,
        bool persistInDatabase)
    {
        if (payload == null || !payload.Any())
        {
            Log.Error($"Collector '{sourceName}': Payload is 'NULL' or empty. Cannot import payload into CMDB.");
            return;
        }

        using (var context = CMDBEntities.GetCMDBContext(persistInDatabase, sourceName))
        {
            foreach (var item in payload)
                Update(context, item.HostName, item.Name, item.SpeedInMhz, item.Count, item.Cores, sourceId,
                    sourceName);

            context.SaveChanges();
        }
    }

    private static void Update(CMDBEntities context, string itemName, string cpuName, int? cpuSpeed,
        int? cpuCount,
        int? cpuCoresPerCpu, int dataSourceId, string sourceName)
    {
        Log.Debug($"Collector '{sourceName}', Item '{itemName}': Lookup item in CMDB...");

        var ci = context.CMDB_ci.FirstOrDefault(
            a => a.name.ToLower().Equals(itemName.ToLower()) &&
                 a.ci_c_status_id == CiStatus.Active && a.delflag == 0 &&
                 (a.ci_c_type_id == CiType.Server || a.ci_c_type_id == CiType.Workstation));

        if (ci == null)
        {
            Log.Debug($"Collector '{sourceName}', Item '{itemName}': Item was not found in CMDB. Skipping...");
            return;
        }

        var deviceType = ci.CMDB_ci_devicetype ??
                             (ci.CMDB_ci_devicetype = new CMDB_ci_devicetype{LastModBy = sourceName, LastModDateTime = Timestamp});

        InsertOrUpdateCpuEntry(context, deviceType, ci, cpuName, cpuSpeed, cpuCount, cpuCoresPerCpu,
            sourceName);
    }

    private static void InsertOrUpdateCpuEntry(CMDBEntities context, CMDB_ci_devicetype deviceType, CMDB_ci ci,
        string cpuName, int? cpuSpeed, int? cpuCount, int? cpuCoresPerCpu, string lastModBy)
    {
        if (!string.IsNullOrEmpty(cpuName))
        {
            var cpu = GetOrCreateCpuTypeEntry(context, ci, cpuName, lastModBy);
            deviceType.ci_c_hardware_cpu_id = cpu.ci_c_hardware_cpu_id;
        }

        if (cpuCount != null)
            deviceType.cpuCount = cpuCount;

        if (cpuCoresPerCpu != null)
            deviceType.cpuCoresPerCpu = cpuCoresPerCpu;

        if (cpuSpeed != null)
            deviceType.cpuSpeed = cpuSpeed;
    }

    private static CMDB_ci_c_hardware_cpu GetOrCreateCpuTypeEntry(CMDBEntities context, CMDB_ci ci,
        string cpuName,
        string sourceName)
    {
        var cpu =
            context.CMDB_ci_c_hardware_cpu.FirstOrDefault(
                a => a.value.ToLower().Equals(cpuName.ToLower()));

        if (cpu != null) return cpu;

        //Create new entry using it's own context.
        using (var cpuContext = CMDBEntities.GetCMDBContext())
        {
            if (ci.ci_c_type_id != null)
            {
                var newCpu = cpuContext.CMDB_ci_c_hardware_cpu.Add(new CMDB_ci_c_hardware_cpu
                {
                    ci_c_type_id = (CiType) ci.ci_c_type_id,
                    value = cpuName,
                    alias = cpuName,
                    delflag = 0,
                    deprecated = false,
                    LastModBy = sourceName,
                    LastModDateTime = Timestamp
                });

                Log.Debug($"Collector '{sourceName}': Creating new CPU-Entry: '{0}'", cpuName);
                cpuContext.SaveChanges();

                return newCpu;
            }
        }

        return null;
    }
 }

第3。 RAM:

 public static class Memory
 {
    private static readonly Logger Log = LogManager.GetCurrentClassLogger();
    private static readonly DateTime Timestamp = DateTime.Now;

    internal static void Update(IReadOnlyCollection<IMemory> payload, string sourceName, int sourceId,
        bool persistInDatabase)
    {
        if (payload == null || !payload.Any())
        {
            Log.Error($"Collector '{sourceName}': Payload is 'NULL' or empty. Cannot import payload into CMDB.");
            return;
        }

        using (var context = CMDBEntities.GetCMDBContext(persistInDatabase, sourceName))
        {
            foreach (var item in payload)
                Update(context, item.HostName, item.SizeInGb, sourceId, sourceName);

            context.SaveChanges();
        }
    }

    private static void Update(CMDBEntities context, string itemName, long? ramSizeInGb, int dataSourceId,
        string sourceName)
    {
        Log.Debug($"Collector '{sourceName}', Item '{itemName}': Lookup item in CMDB...");

        var ci = context.CMDB_ci.FirstOrDefault(
            a => a.name.ToLower().Equals(itemName.ToLower()) &&
                 a.ci_c_status_id == CiStatus.Active && a.delflag == 0 &&
                 (a.ci_c_type_id == CiType.Server || a.ci_c_type_id == CiType.Workstation));

        if (ci == null)
        {
            Log.Debug($"Collector '{sourceName}', Item '{itemName}': Item was not found in CMDB. Skipping...");
            return;
        }

        var deviceType = ci.CMDB_ci_devicetype ??
                             (ci.CMDB_ci_devicetype = new CMDB_ci_devicetype{LastModBy = sourceName, LastModDateTime = Timestamp}); 

        InsertOrUpdateRamSizeEntry(deviceType, ramSizeInGb);
    }

    private static void InsertOrUpdateRamSizeEntry(CMDB_ci_devicetype deviceType, long? ramSize)
    {
        deviceType.ramSize = ramSize;
    }
 }

在极少数情况下,这些方法会同时尝试插入新的设备类型条目,因此EF会崩溃并显示错误消息:

  

2018-02-01 03:54:12.1435 | [错误] | [CMDB.Core.CMDBEntities.SaveChanges]&gt;&gt;&gt;源'CMDB-Collector Discovery(硬件(CPU))':提交对database.System.Data.Entity.Infrastructure.DbUpdateException的更改时发生一般错误更新条目时发生错误。有关详细信息,请参阅内部异常Int32 SaveChanges()   UpdateException更新条目时发生错误。有关详细信息,请参阅内部异常Int32更新()   SqlException违反PRIMARY KEY约束'PK_CMDB_ci_devicetype'。无法在对象'dbo.CMDB_ci_devicetype'中插入重复键。重复键值为(414002)。

我知道原因,但我不知道什么是避免此错误的最佳方法。我可以在每次修改后保存更改,但这会增加处理时间。 或者我可以在不同的任务上添加一些依赖项,以便webservices检查当前正在运行的更新方法并将下一个更新为队列。

谢谢!

更新表格规范:

CREATE TABLE [dbo].[CMDB_ci_devicetype](
[ci_devicetype_id] [bigint] IDENTITY(1,1) NOT NULL,
[ci_id] [bigint] NOT NULL,
[ci_c_devicetype_id] [bigint] NULL,
[ci_c_hardware_cpu_id] [bigint] NULL,
[cpuCount] [int] NULL,
[cpuCoresPerCpu] [int] NULL,
[cpuSpeed] [int] NULL,
[ramSize] [bigint] NULL,
[cpu_processor_type] [varchar](max) NULL,
[cpu_number_of_sockets] [varchar](max) NULL,
[cpu_populate_sockets] [varchar](max) NULL,
[cpu_core_per_populate_sockets] [varchar](max) NULL,
[cpu_core_per_server] [varchar](max) NULL,
[ram] [varchar](max) NULL,
[controller] [varchar](max) NULL,
[LastModBy] [varchar](max) NOT NULL,
[LastModDateTime] [datetime] NOT NULL,

CONSTRAINT [PK_CMDB_ci_devicetype] PRIMARY KEY CLUSTERED (     [ci_id] ASC )WITH(PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON)ON [PRIMARY] )[主要] TEXTIMAGE_ON [主要]

0 个答案:

没有答案