Castle ActiveRecord学习(六)数据验证

时间:2023-03-09 15:21:57
Castle ActiveRecord学习(六)数据验证

参考、来源:http://www.cnblogs.com/Terrylee/archive/2006/04/13/374173.html

https://github.com/castleproject/ActiveRecord/blob/master/docs/validation-support.md

Castle ActiveRecord学习(六)数据验证https://github.com/castleproject/ActiveRecord
https://github.com/castleproject/ActiveRecord/blob/master/docs/validators.md

主要内容

1.概述

2.使用Validation

3.如何扩展

4.深入分析验证

一.概述

在录入数据时,对数据有效性的验证是必不可少的,很多时候我们在UI层上就会做一层验证,但有时也需要在底层做一些必要的处理,这就要用到ActiveRecord中的数据有效性的验证。ActiveRecord为我们提供了如下几个验证:

1.ValidateEmail

2.ValidateIsUnique

3.ValidateRegExp

4.ValidateNonEmpty

5.ValidateConfirmation

需要引入:using Castle.Components.Validator;

二.如何使用

为了使用上面这些验证,我们必须用ActiveRecordValidationBase来代替ActiveRecordBase,即实体类必须继承于ActiveRecordValidationBase。

[ActiveRecord("Customs")]
public class Custom : ActiveRecordValidationBase{ }

ActiveRecordValidationBase类为我们提供了如下一个方法和属性:

IsValid():返回验证是否通过
ValidationErrorMessages:获取验证错误信息数组

[ActiveRecord("Customs")]
public class Custom : ActiveRecordValidationBase
{
//IsValid():返回验证是否通过
//ValidationErrorMessages:获取验证错误信息数组
private int _id;
private string _name;
private string _email;
private string _address;
private string _post;
private string _phone; [PrimaryKey(PrimaryKeyType.Identity)]
public int ID
{
get { return this._id; }
set { this._id = value; }
} [Property, ValidateNonEmpty]
public string Name
{
get { return this._name; }
set { this._name = value; }
} [Property, ValidateEmail]
public string Email
{
get { return this._email; }
set { this._email = value; }
} [Property]
public string Address
{
get { return this._address; }
set { this._address = value; }
} [Property, ValidateRegExp(@"\d{6}")]
public string Post
{
get { return this._post; }
set { this._post = value; }
} [Property, ValidateRegExp(@"(\(\d{3,4}\)|\d{3,4}-)?\d{8}")]
public string Phone
{
get { return this._phone; }
set { this._phone = value; }
} public static void DeleteAll()
{
ActiveRecordBase.DeleteAll(typeof(Custom));
} public static Custom[] FindAll()
{
return ((Custom[])(ActiveRecordBase.FindAll(typeof(Custom))));
}
}

  

三.如何扩展

上面这些验证已经能够满足我们绝大多数的需求,但是我们也可以去添加自己的验证。来看看ActiveRecord中的Validation的类结构图(只画出了部分)

Castle ActiveRecord学习(六)数据验证

需要继承AbstractValidator和继承于AbstractValidationAttribute的类

四.深入分析验证

通过上面的分析我们都知道所有的实体类都继承于ActiveRecordValidationBase基类,那么ActiveRecord是如何通过特性来进行验证的呢?下面我们结合源码进一步分析一下。

我们在属性上加上了验证, Attribute并不做任何实质性的工作,它只是调用验证器进行验证,示例代码:

Model中使用:

using Castle.ActiveRecord;
using Castle.ActiveRecord.Queries;
using NHibernate;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Models
{
[ActiveRecord("UserInfo")]
public class UserInfo : ActiveRecordValidationBase<UserInfo>//必须继承ActiveRecordValidationBase
{
[Validators.ValidateIsUnique ,Property("Name")]//加入验证特性描述
public virtual string Name { get; set; }
   }
}

  

using System;
using System.Collections;
using Castle.ActiveRecord.Framework.Internal;
using NHibernate;
using NHibernate.Classic;
using NHibernate.Criterion;
using Castle.Components.Validator;//需要添加引用
using Castle.ActiveRecord; namespace Models.Validators
{
[Serializable]
public class IsUniqueValidator : AbstractValidator
{
/// <summary>
/// Initializes a new instance of the <see cref="IsUniqueValidator"/> class.
/// </summary>
public IsUniqueValidator()
{
} /// <summary>
/// Perform the check that the property value is unqiue in the table
/// </summary>
/// <param name="instance"></param>
/// <param name="fieldValue"></param>
/// <returns><c>true</c> if the field is OK</returns>
public override bool IsValid(object instance, object fieldValue)
{
Type instanceType = instance.GetType();//需要验证的属性 所在类
string name = fieldValue.ToString();//属性值
       //验证逻辑
if (name == "jay")
{
return true;
}
return false; //ActiveRecordModel model = ActiveRecordBase.GetModel(instance.GetType()); //while (model != null)
//{
// if (model.PrimaryKey != null)
// {
// pkModel = model.PrimaryKey;
// } // model = model.Parent;
//} //if (pkModel == null)
//{
// throw new ValidationFailure("We couldn't find the primary key for " + instanceType.FullName + " so we can't ensure the uniqueness of any field. Validatior failed");
//} //IsUniqueValidator.fieldValue = fieldValue; //SessionScope scope = null;
//FlushMode? originalMode = null;
//if (SessionScope.Current == null /*||
// SessionScope.Current.ScopeType != SessionScopeType.Transactional*/)
//{
// scope = new SessionScope();
//}
//else
//{
// originalMode = ActiveRecordBase.holder.CreateSession(instanceType).FlushMode;
// ActiveRecordBase.holder.CreateSession(instanceType).FlushMode = FlushMode.Never;
//} //try
//{
//return (bool)ActiveRecordMediator.Execute(instanceType, CheckUniqueness, instance);
//}
//finally
//{
// if (scope != null)
// {
// scope.Dispose();
// } // if (originalMode != null)
// {
// ActiveRecordBase.holder.CreateSession(instanceType).FlushMode = originalMode ?? FlushMode.Commit;
// }
//}
} //private object CheckUniqueness(ISession session, object instance)
//{
// ICriteria criteria = session.CreateCriteria(instance.GetType()); // if (Property.Name.Equals(pkModel.Property.Name, StringComparison.InvariantCultureIgnoreCase))
// {
// // IsUniqueValidator is on the PrimaryKey Property, simplify query
// criteria.Add(Expression.Eq(Property.Name, fieldValue));
// }
// else
// {
// object id = pkModel.Property.GetValue(instance, new object[0]);
// ICriterion pKeyCriteria = (id == null)
// ? Expression.IsNull(pkModel.Property.Name)
// : Expression.Eq(pkModel.Property.Name, id);
// criteria.Add(Expression.And(Expression.Eq(Property.Name, fieldValue), Expression.Not(pKeyCriteria)));
// }
// return criteria.List().Count == 0;
//} /// <summary>
/// Builds the error message when the property value is not unique 构造错误消息
/// </summary>
/// <returns></returns>
protected override string BuildErrorMessage()
{
if (!String.IsNullOrEmpty(ErrorMessage))
return ErrorMessage;
return String.Format("{0} is currently in use. Please pick up a new {0}.", Property.Name);
} /// <summary>
/// Gets a value indicating whether this validator supports browser validation. 是否支持客户端验证
/// </summary>
/// <value>
/// <see langword="true"/> if browser validation is supported; otherwise, <see langword="false"/>.
/// </value>
public override bool SupportsBrowserValidation
{
get { return false; }
} /// <summary>
/// Applies the browser validation by setting up one or
/// more input rules on <see cref="IBrowserValidationGenerator"/>.
/// </summary>
/// <param name="config">The config.</param>
/// <param name="inputType">Type of the input.</param>
/// <param name="generator">The generator.</param>
/// <param name="attributes">The attributes.</param>
/// <param name="target">The target.</param>
public override void ApplyBrowserValidation(BrowserValidationConfiguration config, InputElementType inputType,
IBrowserValidationGenerator generator, IDictionary attributes, string target)
{
}
}
}

  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Castle.ActiveRecord.Framework.Validators;
using Castle.Components.Validator; namespace Models.Validators
{
/// <summary>
/// Validate that the property's value is unique in the database when saved
/// </summary>
[Serializable]
public class ValidateIsUniqueAttribute : AbstractValidationAttribute
{
private readonly IValidator validator; /// <summary>
/// Initializes a new instance of the <see cref="ValidateIsUniqueAttribute"/> class.
/// </summary>
public ValidateIsUniqueAttribute()
{
validator = new IsUniqueValidator();
} /// <summary>
/// Initializes a new instance of the <see cref="ValidateIsUniqueAttribute"/> class.
/// </summary>
/// <param name="errorMessage">The error message.</param>
public ValidateIsUniqueAttribute(String errorMessage)
: base(errorMessage)
{
validator = new IsUniqueValidator();
} /// <summary>
/// Constructs and configures an <see cref="IValidator"/>
/// instance based on the properties set on the attribute instance.
/// </summary>
/// <returns></returns>
public override IValidator Build()
{
ConfigureValidatorMessage(validator);
return validator;
}
}
}

  

前台使用:

protected void Button6_Click(object sender, EventArgs e)
{
Models.UserInfo tui = new Models.UserInfo();
tui.Name = TextBox2.Text;
if (tui.IsValid())
{
ltlMsg.Text = "验证通过";
}
else
{
ltlMsg.Text = "验证失败";
}
}

  

五、启动程序时,可以初始化数据、根据模型生成数据表、运行指定的Sql文件创建数据库:

 protected void Application_Start(object sender, EventArgs e)
{
// 在应用程序启动时运行的代码
//AuthConfig.RegisterOpenAuth();
//RouteConfig.RegisterRoutes(RouteTable.Routes);
InitActiveRecord();
} //Castle Record Register Model
private void InitActiveRecord()
{
try
{
//加载配置文件
string NHibernateFilePath = Server.MapPath("~/NHibernate.config");
XmlConfigurationSource source = new XmlConfigurationSource(NHibernateFilePath);
//注册数据模型
ActiveRecordStarter.Initialize(source, typeof(Models.LogInfo), typeof(Models.UserInfo), typeof(Models.ThemeInfo), typeof(Models.CommentInfo), typeof(Models.CategoryInfo));
//根据模型生成数据库
//ActiveRecordStarter.CreateSchema();
//运行指定的数据库脚本生成数据库等
//ActiveRecordStarter.CreateSchemaFromFile("MySqlScript.sql");
}
catch (Exception)
{
throw;
}
}

  

六.使用空属类型

在进行数据库操作时,有时候需要进行空值的处理,在ActiveRecord中给我们提供了一组空属类型,可以方便的进行处理,比如可以这样写属性:

[Property("CreateDate")]
public virtual Nullable<DateTime> CreateDate { get; set; }

七.使用枚举类型

定义:
public enum StatusType
{
Editing = 0,
Published = 1,
Archived = 2
}
[Property("status_id")]
public virtual StatusType Status { get; set; } 使用:
Models.UserInfo userinfo = new Models.UserInfo();
userinfo.Status = Models.UserInfo.StatusType.Archived;

  

八.Hooks
有时候我们会在保存,加载,删除等操作时做一些必需的处理,这时可以通过重载以下三个方法来实现:

BeforeSave(IDictionary state)
BeforeLoad(IDictionary state)
BeforeDelete(IDictionary state)

比如说我们想在保存的时候设置创建时间为当前时间,可以这样去写:

protected override bool BeforeSave(IDictionary state)
{
state["Created"] = DateTime.Now;
return true;
}