我嘲笑DbContext,在我的测试中,我想确保实体被标记为删除。当我在模拟上下文中标记每个对象时,我使用静态字典跟踪每个实体:
public DbEntityEntry<T> Entry<T>(T entity) where T : class
{
var entry = (DbEntityEntry<T>)FormatterServices.GetUninitializedObject(typeof(DbEntityEntry<T>));
var state = entityStates[entity];
entry.State = state;
return entry;
}
public void SetEntityState(object entity, System.Data.EntityState state)
{
entityStates.Add(entity, state);
Entry(entity).State = state;
}
private static Dictionary<object, EntityState> entityStates = new Dictionary<object, EntityState>();
我无法通过DbEntityEntry
实例化Activator.CreateInstance()
,因此我已使用FormatterServices.GetUninitializedObject()
进行实例化。
问题是这一行:
entry.State = state;
尝试分配给此属性会导致:
NullReferenceException: Object reference not set to an instance of an object.
显然,在给定函数名称的情况下,对象不会被初始化,但我不确定为什么我可以在不抛出此异常的情况下分配对象的属性。
FWIW,测试看起来像:
TripManager.DeleteTripsByForeignKey(int carId);
var trip1 = _fakeDbContext.Trips.FirstOrDefault(t => t.TripId == 1);
var entry = _fakeDbContext.Entry(trip1);
Assert.AreEqual(EntityState.Deleted, entry.State);
答案 0 :(得分:0)
FormatterServices.GetUninitializedObject
不会调用该类型的任何构造函数。这意味着具有默认值或在构造函数中设置的字段不会被设置。如果您查看State
属性的定义(https://github.com/mono/entityframework/blob/master/src/EntityFramework/Infrastructure/DbEntityEntry.cs - 请原谅单声道版本的链接),您可以看到setter依赖于_internalEntityEntry
,它在构造函数中设置:
internal DbEntityEntry(InternalEntityEntry internalEntityEntry)
{
_internalEntityEntry = internalEntityEntry;
}
这当然是为什么你不应该弄乱FormatterServices.GetUninitializedObject
:)
如果你真的知道你在做什么,你可以明确地调用内部构造函数并嘲笑InternalEntityEntry
......但这似乎是一个非常糟糕的主意。