将实体对象添加到从Parallel.Foreach循环调用的DBContext对象时出错

时间:2014-10-01 16:39:30

标签: c#-4.0 linq-to-entities entity-framework-5 parallel.foreach

错误: 如果事件源自另一台计算机,则必须随事件一起保存显示信息。

活动中包含以下信息:

  

对象引用未设置为对象的实例。在   System.Data.Objects.ObjectStateManager.DetectConflicts(IList 1 entries) at System.Data.Objects.ObjectStateManager.DetectChanges() at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force) at System.Data.Entity.Internal.Linq.InternalSet 1.ActOnSet(Action action,   EntityState newState,Object entity,String methodName)at   System.Data.Entity.Internal.Linq.InternalSet 1.Add(Object entity)
at System.Data.Entity.DbSet
1.添加(TEntity实体)at   ESHealthCheckService.BusinessFacade.BusinessOperationsLayer.AddErrorToDbObject(例外   例如,Server serverObj,Service windowsServiceObj)

消息资源存在,但在字符串/消息表

中找不到该消息
public void CheckForServerHealth()
        {
            businessLayerObj.SetStartTimeWindowsService();
            List<ServerMonitor> serverMonitorList = new List<ServerMonitor>();
            serverList = businessLayerObj.GetServerList();
            Parallel.ForEach(
          serverList,
          () => new List<ServerMonitor>(),
          (server, loop, localState) =>
          {
              localState.Add(serverStatus(server, new ServerMonitor()));
              return localState;
          },
              localState =>
              {
                  lock (serverMonitorList)
                  {
                      foreach (ServerMonitor serverMonitor in localState)
                      {
                          serverMonitorList.Add(serverMonitor);
                      }
                  }
              });
            businessLayerObj.SaveServerHealth(serverMonitorList);
        }


public ServerMonitor serverStatus(Server serverObj, ServerMonitor serverMonitorObj)
        {
            if (new Ping().Send(serverObj.ServerName, 30).Status == IPStatus.Success)
            {
                serverMonitorObj.Status = true;
                try
                {
                    PerformanceCounter cpu = new PerformanceCounter("Processor", "% Processor Time", "_Total", serverObj.ServerName);
                    serverMonitorObj.CPUUtlilization = (cpu.NextValue());
                }
                catch (Exception ex)
                {
                    businessLayerObj.AddErrorObjectToStaticList(ex, serverObj);
                }

                serverMonitorObj.ServerID = serverObj.ServerID;
                try
                {
                    string[] diskArray = serverObj.DriveMonitor.ToString().Split(':');
                    if (diskArray != null && diskArray.Contains("NA"))
                    {
                        serverMonitorObj.DiskSpace = "NA";
                    }
                    else
                    {
                        serverMonitorObj.DiskSpace = ReadFreeSpaceOnNetworkDrives(serverObj.ServerName, diskArray);
                    }
                }
                catch (Exception ex)
                {
                    businessLayerObj.AddErrorObjectToStaticList(ex, serverObj);
                }

                serverMonitorObj.CreatedDateTime = DateTime.Now;
            }
            else
            {
                serverMonitorObj.Status = false;
                serverMonitorObj.ServerID = serverObj.ServerID;
                //return serverMonitorObj;
            }

            return serverMonitorObj;
        }



public void AddErrorObjectToStaticList(Exception ex, Server serverObj = null, Service windowsServiceObj = null)
        {
            EShelathLoging esLogger = new EShelathLoging();

            esLogger.CreateDatetime = DateTime.Now;
            if (ex.InnerException != null)
            {
                esLogger.Message = (windowsServiceObj == null ? ex.InnerException.Message : ("Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.InnerException.Message));
                //esLogger.Message = "Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.InnerException.Message;
                esLogger.StackTrace = (ex.InnerException.StackTrace == null ? "" : ex.InnerException.StackTrace);
            }
            else
            {
                esLogger.Message = (windowsServiceObj == null ? ex.Message : ("Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.Message));
                //esLogger.Message = "Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.Message;
                esLogger.StackTrace = ex.StackTrace;
            }

            if (serverObj != null)
            {
                esLogger.ServerName = serverObj.ServerName;
            }
            try
            {
                lock (lockObject)
                {
                    esHealthCheckLoggingList.Add(esLogger);
                }
            }
            catch (Exception exe)
            {
                string logEntry = "Application";

                if (EventLog.SourceExists(logEntry) == false)
                {
                    EventLog.CreateEventSource(logEntry, "Windows and IIS health check Log");
                }

                EventLog eventLog = new EventLog();
                eventLog.Source = logEntry;
                eventLog.WriteEntry(exe.Message + " " + exe.StackTrace, EventLogEntryType.Error);
            }
        }

然后调用以下函数将对象从静态列表添加到db对象。

public void AddErrorToDbObject()         {             尝试             {                 foreach(eshealthCheckLoggingList中的EShelathLoging eslogObject)                 {                     锁(lockObject)                     {                         dbObject.EShelathLogings.Add(eslogObject);                     }                 }             }             catch(DbEntityValidationException exp)             {                 string logEntry =“Application”;

            if (EventLog.SourceExists(logEntry) == false)
            {
                EventLog.CreateEventSource(logEntry, "Windows and IIS health check Log");
            }

            EventLog eventLog = new EventLog();
            eventLog.Source = logEntry;
            eventLog.WriteEntry(exp.Message + " " + exp.StackTrace, EventLogEntryType.Error);
        }
        catch (Exception exe)
        {
            string logEntry = "Application";

            if (EventLog.SourceExists(logEntry) == false)
            {
                EventLog.CreateEventSource(logEntry, "Windows and IIS health check Log");
            }

            EventLog eventLog = new EventLog();
            eventLog.Source = logEntry;
            eventLog.WriteEntry(exe.Message + " " + exe.StackTrace, EventLogEntryType.Error);
        }`enter code here`

    }

2 个答案:

答案 0 :(得分:1)

DbSet<T>不是线程安全的,因此您不能同时在多个线程中使用它。看来你正试图通过使用lock来解决这个问题,但你做错了。为此,所有线程都必须共享一个锁对象。像你现在一样,为每个线程设置单独的锁定对象将不会做任何事情。

答案 1 :(得分:0)

请注意,我收到了与我正在处理的应用程序相同的异常,并确定解决问题的最佳方法是添加AsyncLock,因为@svick提到DbSet不是线程安全的。谢谢,@ svick!

我猜你的DbContext在你的businessLayerObj中,所以这是我推荐的,使用Stephen Cleary的优秀Nito.AsyncEx(见https://www.nuget.org/packages/Nito.AsyncEx/):

using Nito.AsyncEx;
// ...

private readonly AsyncLock _dbContextMutex = new AsyncLock();


public void CheckForServerHealth()
{
        using (await _dbContextMutex.LockAsync().ConfigureAwait(false))
        {
            await MyDbContextOperations(businessLayerObj).ConfigureAwait(false);
        }
}

private async Task MyDbContextOperations(BusinessLayerClass businessLayerObj)
{
        await Task.Run(() =>
        {
            // operations with businessLayerObj/dbcontext here...
        });
}