如果您能够帮助我理解为什么在从lodging.DestinationId != 0
中删除检查DbContext.ValidateLodging()
时会抛出ObjectDisposedException,我感谢您,如下所示。
下面给出的示例代码来自Julie的编程实体框架 - DbContext,它可以用来重现异常。
环境: Visual Studio 2012 with Entity Framework 6.0.2
已编辑7/1:包含ObjectDisposedException的StackTrace。
DbContext实施&测试数据
namespace DataAccess
{
public class BagaContext : DbContext
{
public DbSet<Destination> Destinations { get; set; }
public DbSet<Lodging> Lodgings { get; set; }
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
if (result.IsValid)
{
ValidateLodging(result);
}
return result;
}
private void ValidateLodging(DbEntityValidationResult result)
{
var lodging = result.Entry.Entity as Lodging;
// PROBLEM: Removing lodging.DestinationId != 0 causes ObjectDisposedException.
if (lodging != null && lodging.DestinationId != 0)
{
if (Lodgings.Any(l => l.Name == lodging.Name &&
l.DestinationId == lodging.DestinationId))
{
result.ValidationErrors.Add(
new DbValidationError(
"Lodging",
"There is already a lodging named " + lodging.Name +
" at this destination.")
);
}
}
}
public BagaContext()
{
Database.SetInitializer<BagaContext>(new InitializeBagaDatabaseWithSeedData());
}
}
public class InitializeBagaDatabaseWithSeedData : DropCreateDatabaseAlways<BagaContext>
{
protected override void Seed(BagaContext context)
{
context.Destinations.Add(new Destination
{
Name = "Grand Canyon",
Lodgings = new List<Lodging>
{
new Lodging {Name = "Grand Hotel"},
new Lodging {Name = "Dave's Dump"}
}
});
}
}
}
测试DbContext.ValidateEntity实施的代码
namespace Client
{
class Program
{
static void Main(string[] args)
{
CreateDuplicateLodging();
Console.ReadLine();
}
private static void CreateDuplicateLodging()
{
using (var context = new BagaContext())
{
var destination = context.Destinations.FirstOrDefault(d => d.Name == "Grand Canyon");
try
{
context.Lodgings.Add(new Lodging
{
Destination = destination,
Name = "Grand Hotel"
});
context.SaveChanges();
Console.WriteLine("Save Successful");
}
catch (DbEntityValidationException ex)
{
Console.WriteLine("Save Failed: ");
foreach (var error in ex.EntityValidationErrors)
{
Console.WriteLine(
string.Join(Environment.NewLine,
error.ValidationErrors.Select(v => v.ErrorMessage)));
}
}
}
}
}
}
模型类
namespace Model
{
[Table("Locations", Schema = "baga")]
public class Destination
{
public Destination()
{
this.Lodgings = new List<Lodging>();
}
[Column("LocationID")]
public int DestinationId { get; set; }
[Required, Column("LocationName")]
[MaxLength(200)]
public string Name { get; set; }
public virtual List<Lodging> Lodgings { get; set; }
}
public class Lodging
{
public int LodgingId { get; set; }
[Required]
[MaxLength(200)]
[MinLength(10)]
public string Name { get; set; }
[Column("destination_id")]
public int DestinationId { get; set; }
public Destination Destination { get; set; }
}
}
ObjectDisposedException的StackTrace
at System.Data.Entity.Core.Objects.ObjectContext.get_Connection()
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at System.Lazy`1.get_Value()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3[TResult](IEnumerable`1 sequence)
at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.Any[TSource](IQueryable`1 source, Expression`1 predicate)
at DataAccess.BagaContext.ValidateLodging(DbEntityValidationResult result) in c:\Users\User\Documents\Visual Studio 2012\Projects\Learning\EF\StackOverflowQuestions\DataAccess\BreakAwayContext.cs:line 38
at DataAccess.BagaContext.ValidateEntity(DbEntityEntry entityEntry, IDictionary`2 items) in c:\Users\User\Documents\Visual Studio 2012\Projects\Learning\EF\StackOverflowQuestions\DataAccess\BreakAwayContext.cs:line 26
at System.Data.Entity.DbContext.GetValidationErrors()
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at Client.Program.CreateDuplicateLodging() in c:\Users\User\Documents\Visual Studio 2012\Projects\Learning\EF\StackOverflowQuestions\Client\Program.cs:line 34
at Client.Program.Main(String[] args) in c:\Users\User\Documents\Visual Studio 2012\Projects\Learning\EF\StackOverflowQuestions\Client\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
感谢。
答案 0 :(得分:0)
我发现了一个有点hacky的解决方案,但我不知道究竟是什么问题。幸运的是,这可能是测试引发的错误,因为您可能没有计划在测试环境之外使用DropCreateDatabaseAlways。
如果您在播种过程中没有执行任何查询,问题就会消失。一种方法是阻止验证,直到SaveChanges在app域中至少完成一次(在播种期间调用SaveChanges。)一种(可能结束)简单的方法是修改BagaContext
如下:
private static bool _seedingComplete;
public override int SaveChanges()
{
var result = base.SaveChanges();
_seedingComplete = true;
return result;
}
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
if (_seedingComplete && result.IsValid)
{
ValidateLodging(result);
}
return result;
}
同样,我不确切地知道为什么在播种期间执行查询会导致此问题,但如果您能找到避免这种情况的方法,那么您应该没问题。
编辑以添加更多说明:
lodging.DestinationId != 0
中if语句中的子句ValidateLodging
具有防止错误的效果的原因是,在播种期间所有目标记录的ID都为0 ,因为他们尚未插入。因为在播种期间DestinationId将始终为0,所以此子句阻止执行Lodgings.Any(...)
查询。
这个问题让我难以理解的一个原因是,播种期间的Lodgings.Any(...)
查询不会导致抛出异常,但是 中断Lodgings
DbSet,以便以后不能用于实际查询。我花了一段时间才弄清楚DbSet在哪里被破坏了。