zoukankan      html  css  js  c++  java
  • NHibernate Step By Step(3)数据操作回调方法(拦截器)


    1.ILifecycle
    2.IValidatable
    3.Interceptor

    ILifecycle接口

    在数据操作的时候,我们可能需要做些格外的处理,比如Save方法可能就需要一个OnSave方法

    NH提供了ILifecycle接口,用于回调

    该接口包含4个方法,当实体类实现该接口时,session调用这些方法时,将会先检测,以返回的LifecycleVeto枚举作判断,Veto则禁止通过,NoVeto则允许数据操作执行

    image

    如下实体类

    public class EntityWithLifecycle : ILifecycle
        {
            public virtual int Id { get; set; }
            public virtual string Name { get; set; }
            public virtual double Heigth { get; set; }
            public virtual double Width { get; set; }
            public EntityWithLifecycle() {}
            public EntityWithLifecycle(string name, double heigth, double width)
            {
                Name = name;
                Heigth = heigth;
                Width = width;
            }
    
            public virtual LifecycleVeto OnSave(ISession s)
            {
                return IsValid() ? LifecycleVeto.NoVeto : LifecycleVeto.Veto;
            }
    
            public virtual LifecycleVeto OnUpdate(ISession s)
            {
                return IsValid() ? LifecycleVeto.NoVeto : LifecycleVeto.Veto;
            }
    
            public virtual LifecycleVeto OnDelete(ISession s)
            {
                return IsValid() ? LifecycleVeto.NoVeto : LifecycleVeto.Veto;
            }
    
            public virtual void OnLoad(ISession s, object id)
            {
                // nothing to do
            }
    
            public virtual IList<string> GetBrokenRules()
            {
                IList<string> result = new List<string>(3);
                if (string.IsNullOrEmpty(Name) || Name.Trim().Length < 2)
                    result.Add("The Name must have more than one char.");
                if (Heigth <= 0)
                    result.Add("Heigth must be great than 0");
                if (Width <= 0)
                    result.Add("Width must be great than 0.");
                return result;
            }
    
            /// <summary>
            /// Validate the state of the object before persisting it. If a violation occurs,
            /// throw a <see cref="ValidationFailure" />. This method must not change the state of the object
            /// by side-effect.
            /// </summary>
            private bool IsValid()
            {
                IList<string> br = GetBrokenRules();
                return br == null || br.Count == 0;
            }
        }

    测试,将无法保存数据到数据库中

    using (ISession s = OpenSession())
    {
        s.Save(new EntityWithLifecycle());
        s.Flush();
    }

    IValidatable接口

    public interface IValidatable
    {
        /// <summary>
        /// Validate the state of the object before persisting it. If a violation occurs,
        /// throw a <see cref="ValidationFailure" />. This method must not change the state of the object
        /// by side-effect.
        /// </summary>
        void Validate();
    }

    用于验证数据的正确性,实体实现该接口,在保存或更新数据操作时,都会调用此方法,若验证不通过,则抛出ValidationFailure错误

    public class Video: IValidatable
        {
            private int id;
            private string name;
            private double heigth;
            private double width;
    
            public Video() {}
    
            public Video(string name, double heigth, double width)
            {
                this.name = name;
                this.heigth = heigth;
                this.width = width;
            }
    
            public virtual int Id
            {
                get { return id; }
                set { id = value; }
            }
    
            public virtual string Name
            {
                get { return name; }
                set { name = value; }
            }
    
            public virtual double Heigth
            {
                get { return heigth; }
                set { heigth = value; }
            }
    
            public virtual double Width
            {
                get { return width; }
                set { width = value; }
            }
    
            #region IValidatable Members
            public virtual IList<string> GetBrokenRules()
            {
                IList<string> result = new List<string>(3);
                if (string.IsNullOrEmpty(Name) || Name.Trim().Length < 2)
                    result.Add("The Name must have more than one char.");
                if (Heigth <= 0)
                    result.Add("Heigth must be great than 0");
                if (Width <= 0)
                    result.Add("Width must be great than 0.");
                return result;
            }
    
            /// <summary>
            /// Validate the state of the object before persisting it. If a violation occurs,
            /// throw a <see cref="ValidationFailure" />. This method must not change the state of the object
            /// by side-effect.
            /// </summary>
            public virtual void Validate()
            {
                IList<string> br = GetBrokenRules();
                if (br != null && br.Count > 0)
                    throw new ValidationFailure(BrokenRulesFormat(typeof(Video), br));
            }
    
            private static string BrokenRulesFormat(System.Type entity, IList<string> brokenRulesDescriptions)
            {
                if (entity == null)
                    throw new ArgumentNullException("entity");
                if (brokenRulesDescriptions == null)
                    throw new ArgumentNullException("brokenRulesDescriptions");
    
                StringBuilder sb = new StringBuilder(50 + brokenRulesDescriptions.Count * 50)
                    .AppendLine(string.Format("Entity:{0}", entity));
                foreach (string message in brokenRulesDescriptions)
                    sb.AppendLine(message);
    
                return sb.ToString();
            }
    
            #endregion
        }


    测试,程序将跳入catch中

    try
    {
        using (ISession s = OpenSession())
        {
            s.Save(new Video());
            s.Flush();
        }
        Assert.Fail("Saved an invalid entity");
    }
    catch(ValidationFailure)
    {
        // Ok
    }

    以上两种方法需要个别实体全部实现,若数量多的话就麻烦了,于是出现了拦截器

    拦截器

    image

    比如对每次操作写入日志时,可使用此方法

    使用拦截器方法
    1.在session被创建时
    ISession session = sf.OpenSession( new AuditInterceptor() );
    2.在Configuration中声明
    new Configuration().SetInterceptor( new AuditInterceptor() );

    使用拦截器可以拦截到的数据进行修改,所以使用拦截器也需要小心,做的不好,可能会破坏原有程序

    简单示例

    public class StatefulInterceptor : EmptyInterceptor
        {
            private ISession session;
            private readonly IList list = new ArrayList();
    
            public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
            {
                if (!(entity is Log))
                {
                    list.Add(new Log("insert", (string) id, entity.GetType().FullName));
                }
                return false;
            }
    
            public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types)
            {
            if ( !(entity is Log) ) {
                list.Add( new Log( "update", (string) id, entity.GetType().FullName ) );
            }
            return false;
            }
    
            public override void PostFlush(ICollection entities)
            {
                if (list.Count > 0)
                {
                    foreach (object iter in list)
                    {
                        session.Persist(iter);
                    }
                    list.Clear();
                    session.Flush();
                }
            }
    
            public override void SetSession(ISession sessionLocal)
            {
                session = sessionLocal;
            }
    
            public ISession Session
            {
                get { return session; }
            }
        }

    测试
    StatefulInterceptor statefulInterceptor = new StatefulInterceptor();
    ISession s = OpenSession(statefulInterceptor);
    Assert.IsNotNull(statefulInterceptor.Session);
    
    ITransaction t = s.BeginTransaction();
    User u = new User("Gavin", "nivag");
    s.Persist(u);
    u.Password = "vagni";
    t.Commit();
    s.Close();
    
    s = OpenSession();
    t = s.BeginTransaction();
    IList logs = s.CreateCriteria(typeof(Log)).List();
    Assert.AreEqual(2, logs.Count);
    s.Delete(u);
    s.Delete("from Log");
    t.Commit();
    s.Close();
  • 相关阅读:
    正则表达式  语法
    正则表达式  语法
    SQL Server 删除日志文件
    SQL Server 删除日志文件
    C# CLR简介
    C# CLR简介
    理解 C# 项目 csproj 文件格式的本质和编译流程
    理解 C# 项目 csproj 文件格式的本质和编译流程
    De4Dot+Reflector 支持多种反混淆
    De4Dot+Reflector 支持多种反混淆
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1536972.html
Copyright © 2011-2022 走看看