【发布时间】:2011-10-17 19:15:52
【问题描述】:
我目前有一个项目,它使用 Entity Framework 4.1 来登录数据库,这样我们就可以跟踪部署在多个 Web 服务器上的 Web 应用程序。我使用Scott Gu's Code First 解决方案构建了它。
所以,我有这样的代码:
logging.Logs.Add(newLog);
有时会抛出这个错误:
System.NullReferenceException : 对象引用未设置为 对象的实例。在 System.Data.Objects.ObjectStateManager.DetectConflicts(IList
1 entries) at System.Data.Objects.ObjectStateManager.DetectChanges() at System.Data.Entity.Internal.Linq.InternalSet1.ActOnSet(动作动作, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet1.Add(Object entity) at System.Data.Entity.DbSet1.Add(TEntity entity)
大多数情况下它工作正常,但有时会打嗝。当我有多个服务器使用此代码访问/写入同一个数据库时,是否应该注意最佳实践?
现在使用的方法是每个请求都会导致系统将几个新的日志对象添加到集合中,然后保存它们的一组,而不是保存每个单独的日志记录。这是我的课程大纲。
public class LoggingService : ILoggingService
{
Logging.Model.MyLogging logging;
public LoggingService()
{
InitializeLog();
}
/// <summary>
/// Save any pending log changes (only necessary if using the Add methods)
/// </summary>
public void SaveChanges()
{
//ensure that logging is not null
InitializeLog();
logging.SaveChanges();
}
#region Private Methods
private void InitializeLog()
{
if (logging == null)
logging = new Model.MyLogging();
}
private void Log(Level level, int sourceId, string message, bool save, int? siteId = null, int? epayCustomerId = null,
string sessionId = null, int? eventId = null, Exception exception = null)
{
if (sourceId == 0)
throw new ArgumentNullException("sourceId", "The Source Id cannot be null and must be valid.");
var source = (from s in logging.Sources
where s.SourceId == sourceId
select s).FirstOrDefault();
if (source == null)
throw new ArgumentNullException("sourceId", String.Format("No valid source found with Id [{0}].", sourceId));
if (eventId.HasValue)
{
if (eventId.Value > 0)
{
var code = (from e in logging.Events
where e.EventId == eventId.Value
select e).FirstOrDefault();
//if event id was passed in but no event exists, create a "blank" event
if (code == null)
{
Event newCode = new Event()
{
EventId = eventId.Value,
Description = "Code definition not specified."
};
InitializeLog();
logging.Events.Add(newCode);
logging.SaveChanges();
}
}
}
var newLog = new Log()
{
Created = DateTime.Now,
Message = message,
Source = source,
Level = level,
EventId = eventId,
SessionId = sessionId,
SiteId = siteId,
MachineName = System.Environment.MachineName,
};
if (exception != null)
newLog.Exception = String.Format("{0}{1}{2}{1}", exception.Message, Environment.NewLine, exception.StackTrace);
//ensure that the logging is not null
InitializeLog();
logging.Logs.Add(newLog);
if (save)
{
logging.SaveChanges();
}
}
#endregion
}
我将 IoC 与 StructureMap 一起使用,并且我没有将此类初始化为单例。
For<ILoggingService>().Use<LoggingService>();
我的上下文类看起来像这样:
internal class MyLogging : DbContext
{
public DbSet<Source> Sources { get; set; }
public DbSet<Event> Events { get; set; }
public DbSet<Log> Logs { get; set; }
/// <summary>
/// DO NOT ADD ITEMS TO THIS COLLECTION
/// </summary>
public DbSet<LogArchive> LogArchives { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MyDbContextInitializer());
modelBuilder.Entity<Event>().Property(p => p.EventId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<Source>().Property(p => p.SourceId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<LogArchive>().Property(p => p.LogId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
base.OnModelCreating(modelBuilder);
}
//public class MyDbContextInitializer : DropCreateDatabaseIfModelChanges<MyLogging>
public class MyDbContextInitializer : CreateDatabaseIfNotExists<MyLogging>
{
protected override void Seed(MyLogging dbContext)
{
// seed data
base.Seed(dbContext);
}
}
}
我可能在做一些明显错误的事情,但我只是没有看到。
编辑: 根据要求,这是我如何调用日志记录服务代码的示例。此特定方法记录与 HTTP 请求相关的信息。我将日志项附加到一个尝试捕获中并保存在一个单独的尝试捕获中,因此如果出现问题,它至少会保存所添加的内容。处理程序是另一个通过 IoC 注入到此类的服务,它通过电子邮件将错误的详细信息发送给我。
发到服务器的单个帖子可以记录多达 50-70 个单独的详细信息,分成 10-15 个块(http 请求、发送到 Web 服务的数据、Web 服务调用的结果、返回给客户端的响应) ,这就是为什么我要添加分组然后保存分组,而不是打开和关闭与每个单独项目的连接。
public void LogHttpPostStart(HttpPostRequest request)
{
try
{
//if no session is set, use the ASP.NET session
request.SessionId = GetSessionId(request.SessionId);
int eventId = (int)Model.Enums.Logging.Event.SubmittedByClient;
var current = HttpContext.Current;
if (current != null)
{
logService.AddDebug((int)request.Source, String.Format("{0} HTTP Request Details {0}", Header2Token.ToString().PadRight(HeaderTokenCount, Header2Token)),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
//Server Information
logService.AddDebug((int)request.Source, String.Format("Machine Name: {0}", current.Server.MachineName),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
//User Information
logService.AddDebug((int)request.Source, String.Format("User Host Address: {0}", current.Request.UserHostAddress),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("User Host Name: {0}", current.Request.UserHostName),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
//Browser Information
if (current.Request.Browser != null)
{
logService.AddDebug((int)request.Source, String.Format("Browser: {0}", current.Request.Browser.Browser),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("Browser Version: {0}", current.Request.Browser.Version),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("User Agent: {0}", current.Request.UserAgent),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("Is Mobile Device: {0}", current.Request.Browser.IsMobileDevice.ToString()),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
if (current.Request.Browser.IsMobileDevice)
{
logService.AddDebug((int)request.Source, String.Format("Mobile Device Manufacturer: {0}", current.Request.Browser.MobileDeviceManufacturer),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("Mobile Device Model: {0}", current.Request.Browser.MobileDeviceModel),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
}
logService.AddDebug((int)request.Source, String.Format("Platform: {0}", current.Request.Browser.Platform),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("Cookies Enabled: {0}", current.Request.Browser.Cookies.ToString()),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
logService.AddDebug((int)request.Source, String.Format("Frames Enabled: {0}", current.Request.Browser.Frames.ToString()),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
if (current.Request.Browser.JScriptVersion != null)
{
logService.AddDebug((int)request.Source, String.Format("Javascript Version: {0}", current.Request.Browser.JScriptVersion.ToString()),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
}
}
logService.AddDebug((int)request.Source, String.Format("{0} End HTTP Request Details {0}", Header2Token.ToString().PadRight(HeaderTokenCount, Header2Token)),
siteId: request.SiteId, epayCustomerId: request.EPayCustomerId, sessionId: request.SessionId,
eventId: eventId);
}
}
catch (Exception ex)
{
handler.HandleError(true, ex);
}
try
{
logService.SaveChanges();
}
catch (Exception ex)
{
handler.HandleError(true, ex);
}
}
【问题讨论】:
-
SQL Server?还是另一个数据库和提供者?为什么你到处都有这些
InitializeLog电话?你在构造函数中初始化上下文,这还不够吗?如果您真的在SaveChanges方法中创建一个新上下文,然后立即调用该上下文的SaveChanges,则不会发生任何事情,因为上下文是空的。如果上下文是null,我宁愿让应用程序崩溃,因为那时可能有问题。如果你默默地创建一个新的上下文,你可能会错过一个重要的错误。 -
Sql Server 2008 R2。感谢您的指点。我会把它清理干净。
标签: entity-framework-4 ef-code-first