想象一下如下所示的数据库表:
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 select来做这个,我觉得nHibernate中有一些东西与触发器和事件监听器的使用,但是任何人都可以告诉我如何实现nHibernate存储库,所以我可以:
修改
所以,这里有一些混乱,也许我解释错了......我想要做的就是这样,总是得到当前记录......
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的愤怒,我不会把它从他身上移走,因为他把我带到了正确的道路上......我最终得到的是:
在创建/更新内部,过程如下:
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;
}
在删除方法中,我们只需更新{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。希望它可以帮助那些处于我处境的人。
答案 0 :(得分:0)
public UserMap : ClassMap<User>
{
public UserMap()
{
Where("id = currentid"); // always bring back the most recent
}
}
// in Userrepository
public void Update(User user)
{
var clone = user.Clone();
session.Evict(user); // to prevent flushing the changes
var newId = session.Save(clone);
session.CreateQuery("UPDATE User u SET u.currentid = :current") // <-- hql
.SetParameter("current", newId)
.ExecuteUpdate();
}
使用这个简单的代码,对象图更加棘手。然后我会做以下其中一项:
我曾经看过一个仅附加模型做类似下面的事情
// UserBase is there to ensure that all others referencing the User doesnt have to update because user properties changed
class UserBase
{
public virtual int Id { get; set; }
public virtual ICollection<PersonDetails> AllDetails { get; private set; }
public virtual PersonDetails CurrentDetails
{
get { return _currentDetauils; }
set { _currentDetauils = value; AllDetails.Add(value); }
}
// same as above
public virtual ICollection<ConfigDetails> AllConfigs { get; set; }
}
class Order
{
public virtual int Id { get; set; }
public virtual UserBase User { get; set; }
public virtual IList<OrderDetail> AllDetails { get; private set; }
public virtual IList<OrderDetail> ActiveDetails { get; private set; }
public virtual void Add(OrderDetail detail)
{
AllDetails.Add(detail);
ActiveDetails.Add(detail);
}
public virtual void Delete(OrderDetail detail)
{
detail.Active = false;
ActiveDetails.Remove(detail);
}
}
class OrderDetail
{
public virtual int Id { get; set; }
public virtual Order Parent { get; set; }
public virtual bool Active { get; set; }
}
class OrderMap : ClassMap<Order>
{
public OrderMap()
{
HasMany(o => o.AllDetails);
HasMany(o => o.ActiveDetails).Where("active=1");
}
}
// somewhere
public void UpdateTaxCharge(OrderDetail detail, TaxCharge charge)
{
var clone = detail.Clone();
clone.TaxCharge = charge;
detail.Order.Delete(detail);
detail.Order.Add(clone);
}
答案 1 :(得分:0)
你可以告诉NHibernate在持久化和加载实体时它应该生成什么SQL。例如,您可以告诉NHibernate使用存储过程而不是纯SQL语句。如果这是你的选择,我可以进一步阐述我的答案。