NHibernate初学者指南(18):验证单个属性

表示层简单的验证,我们可以使用基于对象属性内容的验证。在NHibernate Contributions中有一个可用的项目NHibernate.Validator。可以通过SVN下载NHibernate Contribution项目的源代码:地址是https://nhcontrib.svn.sourceforge.net,也可以通过NuGet获得。

配置验证器

一旦在解决方案中引用了NHibernate.Validator程序集,我们就需要配置验证引擎。为此,该项目定义了一个fluent API。首先,我们必须定义一个验证器配置的实例,如下面的代码所示:

var nhvConfig =new NHibernate.Validator.Cfg.Loquacious.FluentConfiguration();

注意这跟NHibernate配置不一样。

现在可以使用fluent API配置前面的配置对象和定义:

  • 我们想使用哪个验证模式
  • 可以在哪里找到验证定义
  • 如何将验证和NHibernate整合
nhvConfig
        .SetDefaultValidatorMode(ValidatorMode.UseAttribute)
        .Register(typeof(Product).Assembly.ValidationDefinitions())
        .IntegrateWithNHibernate
        .ApplyingDDLConstraints()
        .And
        .RegisteringListeners();

在上面的代码中,我们使用特性定义验证规则。还指示验证引擎解析我们定义的实体程序集。最后,请求验证引擎使用元信息应用到模型来丰富架构定义(调用ApplyDDLConstraints),还请求它定义两个使用NHibernate的截获器,无论何时插入或更新实体时都透明的验证属性(调用RegisteringListeners)。

有了这个验证配置,就可以创建验证引擎对象并使用前面的配置对象配置它了。如下面的代码所示:

var validatorEngine = new ValidatorEngine();
validatorEngine.Configure(nhvConfig);

最后为NHibernate配置对象使用由NHibernate.Validator项目定义的Initialize扩展方法。验证引擎对象作为Initialize方法的参数,如下面的代码所示:

nhibernateConfig.Initialize(validatorEngine); 

在所有设置之后,我们准备创建或重新创建数据库架构,使用NHibernate的SchemaExport类,如下面的代码所示:

new SchemaExport(c).Execute(false, true, false); 

定义验证规则

完成了系统的配置和数据库架构的创建,就可以使用特性声明实体了。

每个特性都定义有一个Message参数,用于验证失败时显示的信息。最常用的一个特性还有NotNull,表示属性不能为空。一个产品必须有一个合法的名字,如下面的代码所示:

[NotNull(Message = "Product must have a valid name")]
public string Name { get; set; }

通常,Product实体的Name必须至少有一个或两个且不超过50个字符。我们可以使用Length特性验证:

[NotNull(Message = "Product must have a valid name")]
[Length(Min = 2, Max = 50, Message = "Name of product must be between 1 and 50 char")]
public string Name { get; set; }

如上面的例子,我们可以在一个属性上定义多个特性。

Fluent方式配置验证规则

如果不想在模型的属性上使用特性验证,我们可以使用NHibernatevalidator提供的fluent API配置实体的验证。

为我们想验证的每个实体定义一个继承自ValidationDef<T>的类,T表示我们想验证的实体。如果想验证Product实体,我们可以定义下面的类:

public class ProductValidator : ValidationDef<Product>
{ }

在上面类的构造函数中,我们使用NHibernate.Validator提供的fluent API以声明方式定义实体的验证逻辑。获得和前面的例子中相同的结果,我们可以使用下面的代码:

public ProductValidator()
{
    Define(x => x.Name)
    .NotNullable()
    .WithMessage("The product name cannot be undefined")
    .And
    .LengthBetween(2, 50)
    .WithMessage("Product name must be between 2 and 50 char");
}

执行验证

配置验证器的时候,我们注册了两个NHibernate监听器,当实体插入或更新时就会触发它们。如果实体处于不合法的状态,监听器就会抛出异常。

通常,我们不希望在验证失败时抛出异常。好点的解决方案就是在保存或更新实体之前就验证它们。如下面的代码所示:

var product = new Product {...};
var validator = new ValidatorEngine();
var invalidValues = validator.Validate(product);
if (invalidValues.Length > 0)
    ShowInvalidValues(product, invalidValues);
else
    session.Save(product);

上面的代码中,我们创建了一个product实体,然后使用验证引擎验证product。验证方法返回InvalidValue对象的数组。如果产品合法,数组的长度为0,否则数组的每个元素包含验证失败的信息。如果验证成功了,我们只保存产品,否则显示出验证失败的信息,如下面的代码所示:

private static void ShowInvalidValues(object entity, IEnumerable<InvalidValue> invalidValues)
{
    Console.WriteLine(entity.GetType().Name);
    foreach (var invalidValue in invalidValues)
        Console.WriteLine(" Property {0}: {1}",
        invalidValue.PropertyName,
        invalidValue.Message);
}

下面我们完成一个例子。

使用属性验证

在这个例子中,我们想实现一个简单的模型,通过在属性上声明来验证。

1. 在MMSM中创建一个空数据库:BasicValidationSample。

2. 在Visual Studio中,创建一个控制台应用程序:BasicValidtionSample,并设置项目的Target framework为.NET Framework 4.0。

3. 添加对Castle.Core.dll, FluentNHibernate.dll,Iesi.Collections.dll, NHibernate.dll, NHibernate.ByteCode.Castle.dll程序集的引用,NHibernate.Validator我们通过NuGet添加。

4. 在Solution Explorer中,右击References文件夹,选择"Add Library Package Reference…"(在我的电脑上是Manage NuGet Packages),在弹出的对话框中,在左边选择Online,然后在搜索框中输入NHibernate.Validator,然后安装即可,如下图所示:

5. 在项目中添加一个Category类,如下所示:

public class Category
{
    public virtual Guid Id { get; set; }
    [NotNullNotEmpty(Message = "The category name cannot be undefined.")]
    [Length(Min = 2, Max = 50, Message ="The category name must be between 2 and 50 characters long")]
    public virtual string Name { get; set; }
}

Category的Name属性不能为空,且长度在2到50之间。

6. 添加Category的映射类CategoryMap,如下面的代码所示:

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();
        Map(x => x.Name);
    }
}

7. 在项目中添加一个Product类,代码如下所示:

public class Product
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    [NotNull]
    public virtual Category Category { get; set; }
    [NotNull]
    public virtual decimal UnitPrice { get; set; }
    [NotNull]
    [Min(1, Message = "Units on stock must be a positive number.")]
    public virtual int UnitsOnStock { get; set; }
    [NotNull]
    [Min(1, Message = "Reorder level must be a positive number.")]
    public virtual int ReorderLevel { get; set; }
    [NotNull]
    public virtual bool Discontinued { get; set; }
}

Category,UnitPrice,UnitsOnStock,ReorderLevel,Discontinued都不能为空,UnitsOnStock和ReorderLevel必须是正数。

8. 添加Product的映射类ProductMap,代码如下所示:

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();
        Map(x => x.Name);
        References(x => x.Category);
        Map(x => x.UnitPrice);
        Map(x => x.UnitsOnStock);
        Map(x => x.ReorderLevel);
        Map(x => x.Discontinued);
    }
}

9. 在Program类中定义一个连接字符串,如下面的代码所示:

const string connString =
            "server=.;database=BasicValidationSample;" +
            "integrated security=true";

10. 在Program类中的Main方法中,使用Fluent NHibernate的API创建一个session工厂,代码如下所示:

static void Main(string[] args)
{
    var factory = Fluently.Configure()
                .Database(MsSqlConfiguration
                .MsSql2008
                .ConnectionString(connString)
                .ShowSql()
                )
                .Mappings(m => m.FluentMappings
                .AddFromAssemblyOf<Product>()
                )
                .ExposeConfiguration(ExportSchema)
                .BuildSessionFactory();
    Console.Write("Hit enter to exit:");
    Console.ReadLine();
}

11. 我们需要实现上面代码中由ExposeCofiguration方法调用的ExportSchema方法。在这个方法中,我们配置验证引擎,然后使用这个验证其配置初始化NHibernate配置,如下面的代码所示:

private static void ExportSchema(Configuration c)
{
    var nhvConfig = new NHibernate.Validator.Cfg.Loquacious.FluentConfiguration();

    nhvConfig.SetDefaultValidatorMode(ValidatorMode.UseAttribute)
    .Register(typeof(Product).Assembly.ValidationDefinitions())
    .IntegrateWithNHibernate
    .ApplyingDDLConstraints().And.RegisteringListeners();
    var validatorEngine = new ValidatorEngine();
    validatorEngine.Configure(nhvConfig);

    ValidatorInitializer.Initialize(c, validatorEngine);
    new SchemaExport(c).Execute(true, true, false);
}

在上面的例子中,我们通过NuGet快速添加了NHibernate.Validator.dll程序集,然后在我们的实体上声明了验证特性,最后配置NHibernate使用验证引擎在持久化到数据库之前验证实体。

posted @ 2011-11-28 21:14  BobTian  阅读(2524)  评论(3编辑  收藏  举报