Fluent NHibernate:如何设置中间表的默认值

时间:2016-03-18 15:00:44

标签: c# asp.net-mvc nhibernate fluent-nhibernate

我正在开发一个.NET MVC应用程序,它使用NHibernate和Fluent NHibernate进行映射。我有User和Role表/类,它们通过中间表UserRole映射。所以我的映射工作正常;我有用户映射:

HasManyToMany(user => user.Roles).Cascade.SaveUpdate()

因此,当我用一个新角色保存用户时,它会尝试插入一个新的UserRole行。大。

唯一的问题是我在UserRole表上有不可为空的审计列(如" UpdatedBy"和" UpdatedDate")。我尝试在UserRole构造函数中设置它们,但显然永远不会被调用,因为流畅的Nhibernate只是直接进入数据库并尝试插入没有审计列的新UserRoles。

所以我只是想知道是否有任何干净的方法来为Fluent Nhibernate中的这些列设置默认值。我可以关闭级联,并在保存用户时手动执行所有操作,但我想知道是否有更简洁明了的方法来执行此操作。

1 个答案:

答案 0 :(得分:0)

使用像Envers这样的完整审核系统,或为自定义审核用例添加一些拦截器。

但是在关联表中添加其他属性会导致它难以作为纯关联表处理,只能通过多对多关系进行映射。

您可能更容易将其映射为中间实体(然后最好添加一个代理键),通过多对一关系链接到您的用户和角色实体。

拦截器会对任何更新或插入做出反应并相应地设置审计属性。对于实体和映射的审计属性,这很容易。对于您的情况,您必须修补发出的SQL。

这是我使用的,设置创建者(映射到某个用户实体而不是可空),创建日期(映射而不是可空),更新程序,更新日期(映射和空白)。 (改编自this NH reference examplethis blog post。)

对于您的情况,您可能需要向SqlString OnPrepareStatement(SqlString sql)void OnCollectionUpdate(object collection, object key)添加替换void OnCollectionRecreate(object collection, object key)

// Interceptor setting up audit properties.
[Serializable]
public class AuditInterceptor : NHibernate.EmptyInterceptor
{
    public YourAppUser AppUser { get; set; }

    public override bool OnFlushDirty(object entity,
        object id,
        object[] currentState,
        object[] previousState,
        string[] propertyNames,
        NHibernate.Type.IType[] types)
    {
        var modified = false;
        for (int i = 0; i < propertyNames.Length; i++)
        {
            switch (propertyNames[i])
            {
                case "UpdateDate":
                    currentState[i] = DateTimeOffset.Now;
                    modified = true;
                    break;
                case "Updater":
                    currentState[i] = AppUser;
                    modified = true;
                    break;
            }
        }
        return modified;
    }

    public override bool OnSave(object entity,
        object id,
        object[] state,
        string[] propertyNames,
        NHibernate.Type.IType[] types)
    {
        var modified = false;
        for (int i = 0; i < propertyNames.Length; i++)
        {
            switch (propertyNames[i])
            {
                case "CreationDate":
                    state[i] = DateTimeOffset.Now;
                    modified = true;
                    break;
                case "Creator":
                    state[i] = AppUser;
                    modified = true;
                    break;
            }
        }
        return modified;
    }
}

打开会话时注入拦截器实例:

yourNHibernateSessionFactory.OpenSession(yourInterceptorInstance);

在业务逻辑处理其工作之前,您应该设置当前用户的拦截器。在我的例子中,我在动作过滤器OnActionExecuting方法中执行此操作,使用依赖项解析器获取我的拦截器,该拦截器具有每个http请求生命周期管理器。

此拦截器假定名为CreatorUpdater的任何属性都是AppUser属性,名为CreateDateUpdateDate的任何属性都是{{1} }。例如,您可以通过检查datetimeoffset是否实现某些自定义接口(某些检查类似于entity来保证这样的假设,如参考示例所做的那样)。或者您也可以查看if (!(entity is IYourAuditableInterface)) return false;参数。