取代数据库结构中的子句
想象一个如下所示的数据库表:
create table [dbo].[user]
(
id int IDENTITY(1,1),
username varchar(50) NOT NULL,
firstname varchar(20) NOT NULL,
lastname varchar(30) NOT NULL,
currentid int NULL,
processedby varchar(50) NOT NULL,
processeddate varchar(50) NOT NULL
processedaction varchar(50) NOT NULL
)
我想要做的是设置 NHibernate 将其加载到我的用户对象中,但我只想恢复对象“user”的当前版本。我知道如何自己执行 SQL 选择来执行此操作,并且我感觉 nHibernate 中好像有一些使用触发器和事件侦听器的东西,但是任何人都可以告诉我如何实现 nHibernate 存储库,以便我可以:
- {Repository }.GetCurrent(id) <- 向其传递分配给任何历史记录或当前记录的任何 id,并获取当前对象。
- {Repository}.Save(user) <- 我希望始终将更改插入新行,然后更新旧版本以链接回新 ID。
编辑
所以,这里有一些混乱,也许我解释错了...我想做的是这样的,关于总是取回当前记录...
Select uc.*
FROM User uo
JOIN User uc on uo.currentid=uc.id
WHERE uo.id==:id
但是,我不想暴露“CurrentID “对于我的对象模型,因为它与系统的其余部分没有关系,恕我直言。在上面的SQL语句中,uo被认为是“原始”对象集,uc被认为是系统中的当前对象。
编辑#2:
将此视为一个可能的解决方案。 http://ayende.com/blog/4196/append-only-models -with-nhibernate
老实说,我很顽固,因为我正在向后思考这个问题。在这种运行数据库的方式中,自动增量字段应该是版本字段,“id”字段应该是初始插入时自动增量器的值。
回答:
我不想承受 @Firo 的愤怒,我也不会从他身上删除它,因为他带我走上了正确的道路......我最终得到的是:
- 创建了一个带有两个的基本泛型类给出的类型 一个。对象“ID”的类型 b.对象本身的类型。
- 实例化所有类。
- 创建一个通用接口 IRepository 类,其中包含要存储/检索的对象类型。
- 使用要存储/检索的对象类型创建一个抽象泛型类。
- 为每种要存储/检索的类型创建一个具体的实现类。
在创建/更新内部,过程如下所示:
类型提交(类型项目) { var 克隆 = item.DeepClone(); _Session.Evict(项目); 克隆.Id = 0; 克隆.ProcessedDate = DateTime.Now; if (克隆.Action.HasValue) { if (clone.Action == ProcessedAction.Create) 克隆.Action = ProcessedAction.Update; } 别的 { 克隆.Action = ProcessedAction.Create; } clone.ProcessedBy = UserRepos.Where(u => u.Username == System.Threading.Thread.CurrentPrincipal.Identity.Name).First().Current; var saveItem = (_Session.Merge(clone) as Type); _Session.CreateQuery("更新类型设置 CurrentID = :newID 其中 ID=:newID 或 CurrentID=:oldID") .SetParameter(“newID”,savedItem.Id) .SetParameter("oldID", item.Id) .执行更新(); 返回已保存的项目; }
在删除方法中,我们只需更新 {object}.Action = ProcessedAction.Delete
我想用另一种方式做到这一点,但意识到我们最终需要进行历史比较,我们无法要求 nHibernate 过滤已删除的对象,因为用户会想要查看 那。我们将创建一个业务外观来处理已删除的记录。
再次非常感谢@Firo 对此的帮助。
因此,有了这些,我终于可以做到这一点:
var result = {Repository}.Where(obj => obj.Id == {objectID from caller}).FirstOrDefault();
if (result != null)
{
return result.Current;
}
else
{
return null;
}
并且始终为任何请求 ID 取回我当前的对象。希望它对处于我这种情况的人有所帮助。
Imagine a database table that looks like this:
create table [dbo].[user]
(
id int IDENTITY(1,1),
username varchar(50) NOT NULL,
firstname varchar(20) NOT NULL,
lastname varchar(30) NOT NULL,
currentid int NULL,
processedby varchar(50) NOT NULL,
processeddate varchar(50) NOT NULL
processedaction varchar(50) NOT NULL
)
What I want to do is to setup NHibernate to load it into my user object, but I only want the current version of the object "user" to be brought back. I know how to do a SQL select to do this on my own, and I feel as if there's something in nHibernate with the usage of triggers and event listeners, but can anyone tell me how to implement the nHibernate repository so I can:
- {Repository}.GetCurrent(id) <- pass it any of the ids that are assigned to any of the historical or the current record, and get back the current object.
- {Repository}.Save(user) <- I want to always insert the changes to a new row, and then update the old versions to link back to the new id.
Edit
So, there's some confusion here, and maybe I explained it wrong... What I'm trying to do is this, in regards to always getting the current record back...
Select uc.*
FROM User uo
JOIN User uc on uo.currentid=uc.id
WHERE uo.id==:id
But, I don't want to expose "CurrentID" to my object model, since it has no bearing on the rest of the system, IMHO. In the above SQL statement, uo is considered the "original" object set, and uc is considered the current object in the system.
Edit #2:
Looking at this as a possible solution.
http://ayende.com/blog/4196/append-only-models-with-nhibernate
I'm honestly being pigheaded, as I'm thinking about this backward. In this way of running a database, the autoincrementing field should be the version field, and the "id" field should be whatever the autoincrementer's value has at the time of the initial insert.
Answer:
I don't want to take @Firo's fury, and I'm not going to remove it from him, as he took me down the right path... what I wound up with was:
- Created a base generic class with two types given
a. type of the object's "ID"
b. type of the object itself. - instantiate all classes.
- create a generic interface IRepository class with a type of the object to store/retrieve.
- create an abstract generic class with a type of the object to store/retrieve.
- create a concrete implementation class for each type to store/retrieve.
inside of the create/update, the procedure looks like:
Type Commit(Type item) { var clone = item.DeepClone(); _Session.Evict(item); clone.Id = 0; clone.ProcessedDate = DateTime.Now; if (clone.Action.HasValue) { if (clone.Action == ProcessedAction.Create) clone.Action = ProcessedAction.Update; } else { clone.Action = ProcessedAction.Create; } clone.ProcessedBy = UserRepos.Where(u => u.Username == System.Threading.Thread.CurrentPrincipal.Identity.Name).First().Current; var savedItem = (_Session.Merge(clone) as Type); _Session.CreateQuery("UPDATE Type SET CurrentID = :newID where ID=:newID OR CurrentID=:oldID") .SetParameter("newID", savedItem.Id) .SetParameter("oldID", item.Id) .ExecuteUpdate(); return savedItem; }
In the delete method, we simply update the {object}.Action = ProcessedAction.Delete
I wanted to do this another way, but realizing we need to eventually do historical comparisons, we weren't able to ask nHibernate to filter the deleted objects, as the users will want to see that. We'll create a business facade to take care of the deleted records.
Again, much thanks to @Firo for his help with this.
So, with all that, I can finally do this:
var result = {Repository}.Where(obj => obj.Id == {objectID from caller}).FirstOrDefault();
if (result != null)
{
return result.Current;
}
else
{
return null;
}
and always get my current object back for any requesting ID. Hope it helps someone that is in my situation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在映射中,如果您使用 FluentNHibernate
对象图,则使用这个简单的代码会更加棘手。然后我会执行以下操作之一:
我曾经看到一个仅附加模型执行如下操作
in mapping if you use FluentNHibernate
objectgraphs are a lot trickier with this simple code. I would then do one of the following:
i once saw an append-only-model doing something like the following
您可以告诉 NHibernate 在持久化和加载实体时应该生成什么 SQL。例如,您可以告诉 NHibernate 使用存储过程而不是普通的 SQL 语句。如果这是您的选择,我可以进一步阐述我的答案。
You can tell NHibernate what exactly SQL it should generate when persisting and loading an entity. For example you can tell NHibernate to use a stored procedure instead of a plain SQL statement. If this is an option for you I can farther elaborate my answer.