【发布时间】:2009-06-11 20:30:07
【问题描述】:
这两周是我第一次使用 Castle ActiveRecord 以及整个 ActiveRecord 模式。我正在开发一个经常使用它的大型系统,并且在处理它时发现了一些奇怪的 SQL 事务问题(如下面的问题)。我将给出一个让我完全难过的简化版本:
背景:
我有一个 ActiveRecord 类,我们称之为 User。
假设这个用户有很多“宠物”对象。
[ActiveRecord]
public class User: PersistentBase<User>
{
//...
[PrimaryKey]
public long Id
{
get;
set;
}
/// <summary>
/// Date and time the object was first persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime CreationDate
{
get;
set;
}
/// <summary>
/// Date and time the object was last persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime ModificationDate
{
get;
set;
}
/// <summary>
/// Property used for optimistic concurrency
/// </summary>
[Version]
public int LockCount { get; set; }
[HasMany(typeof(Pet), Cascade = ManyRelationCascadeEnum.SaveUpdate, Lazy = false, OrderBy = "Id")]
public IList<Pet> Pets { get; private set; }
//...
protected override bool BeforeSave(IDictionary state)
{
bool retval = base.BeforeSave(state);
DateTime now = DateTime.Now;
state["CreationDate"] = now;
state["ModificationDate"] = now;
return retval;
}
/// <summary>
/// Called when a dirty object is going to be updated in the db. Use this
/// hook to update ModificationDate.
/// </summary>
/// <param name="id"></param>
/// <param name="previousState"></param>
/// <param name="currentState"></param>
/// <param name="types"></param>
/// <returns></returns>
protected override bool OnFlushDirty(object id, IDictionary previousState, IDictionary currentState, IType[] types)
{
bool retval = base.OnFlushDirty(id, previousState, currentState, types);
currentState["ModificationDate"] = DateTime.Now;
return retval;
}
}
[ActiveRecord]
public class Pet : PersistentBase<Pet>
{
[PrimaryKey]
public long Id
{
get;
set;
}
/// <summary>
/// Date and time the object was first persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime CreationDate
{
get;
set;
}
/// <summary>
/// Date and time the object was last persisted to the database
/// </summary>
[Property, ValidateNonEmpty]
public DateTime ModificationDate
{
get;
set;
}
/// <summary>
/// Property used for optimistic concurrency
/// </summary>
[Version]
public int LockCount { get; set; }
//...
[BelongsTo("OwnerId")]
public User User { get; set; }
//...
protected override bool BeforeSave(IDictionary state)
{
bool retval = base.BeforeSave(state);
DateTime now = DateTime.Now;
state["CreationDate"] = now;
state["ModificationDate"] = now;
return retval;
}
/// <summary>
/// Called when a dirty object is going to be updated in the db. Use this
/// hook to update ModificationDate.
/// </summary>
/// <param name="id"></param>
/// <param name="previousState"></param>
/// <param name="currentState"></param>
/// <param name="types"></param>
/// <returns></returns>
protected override bool OnFlushDirty(object id, IDictionary previousState, IDictionary currentState, IType[] types)
{
bool retval = base.OnFlushDirty(id, previousState, currentState, types);
currentState["ModificationDate"] = DateTime.Now;
return retval;
}
}
现在,它们都有自动 Id 字段(由 SQL Server 2005 处理)。
问题:
如果我继续向已经拥有宠物的用户添加新宠物并保存该用户,我会查看是否运行 SQL Profiler,每只宠物都已对它们进行了 UPDATE 调用...但是一个都没有改变。
我到处设置断点,发现当我保存用户时,每只宠物都调用了“OnFlushDirty”(同样,虽然它们从未改变过)。
查看(并偶尔修改)这些用户和宠物的外部进程最终会导致严重的事务问题,如果上述方案仅插入添加的宠物(而不是更新之前的宠物),则可以完全避免这种情况'没有改变)。
问题:
就确保不会发生这种情况而言,我是否在做以上绝对不能做的事情?
感谢您提供的任何帮助!
* 编辑 1:OnFlushDirty 具有 null previousState._values *
编辑:哦!我差点忘了最奇怪的部分!
当在这些 Pets 上调用 OnFlushDirty 时,previousState 和 currentState 存在...它们(作为字典)都有一个内部变量 _values,它应该具有先前和当前状态的值...
... 只有 currentStates 填充了这个变量。 previousState 的“_values”变量设置为“null”。请注意,这适用于以前存在的所有宠物。 previousState 应该总是填充一些东西,对吧?
* 编辑 2:替换自动属性后... *
我用带有属性访问器的传统私有成员替换了自动属性列表。这似乎没有什么不同。我将 NHProfiler 放在系统上,发现如果我通过 IIS 运行 NHProfiler (我在 Visual Studio 2008 中使用 IIS7/Win7),NHProfiler 无法连接到我的 Web 应用程序。
我想我会尝试改用 Visual Studio 的“ASP.NET 开发服务器”来查看 NHProfiler 是否会看到该应用程序。
当我这样做时发生了两件事:
1) NHProfiler 看到我的应用并开始收集数据 2) 对孩子进行的多次更新消失了
但是,切换回 IIS7/Win7 后,多个更新仍在继续。
这是否意味着它可能存在某种配置问题?据我所知,在使用不同的服务器类型时,除了我导航到的 URL(IIS 中的http://localhost,ASP.NET 开发服务器中的http://localhost:(some_random_port))之外,我的配置中的任何内容都不应更改。那么为什么上面的两种情况会突然发生变化呢?
【问题讨论】:
标签: c# database activerecord transactions castle-activerecord