• 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使用验证引擎在持久化到数据库之前验证实体。

  • 相关阅读:
    Educational Codeforces Round 30 B【前缀和+思维/经典原题】
    Educational Codeforces Round 30 A[水题/数组排序]
    洛谷 P2415 集合求和【数学公式/模拟】
    洛谷 P2689 东南西北【模拟/搜索】
    洛谷 P1012 拼数 [字符串]
    codeforces 869C The Intriguing Obsession【组合数学+dp+第二类斯特林公式】
    洛谷 P3927 SAC E#1
    洛谷P3929 SAC E#1
    洛谷P3926 SAC E#1
    codeforces 868B The Eternal Immortality【暴力+trick】
  • 原文地址:https://www.cnblogs.com/nianming/p/2266721.html
Copyright © 2020-2023  润新知