[原创]Fluent NHibernate之旅二--Entity Mapping

接着上一篇,今天我们说说ORM中的Mapping。如果你要体验NHibernate的强大,首先你就要学会配置,包括SessionFactory和Mapping的配置。今天跟上一篇一样,会使用传统方式和 NHibernate 进行讲解。如果你要亲手试验一下,可以先看一下“Fluent NHibernate之旅一”,进行一下数据库和SessionFactory的准备。

本节内容:

  • 简单实体映射
  • 使用自定义类型映射实体属性

NHibernate的实体映射(Entity Mapping)做的非常好,虽然不是完美,但一些我们经常使用的,基本上已经都支持了,而且配置也相对比较简单。好了,开始我们的体验之旅吧。

一、简单实体映射

为了配合今后的教程,我们以一个简单的电子商务平台说起。一个B2C的电子商务,我们一定需要产品和订单,因为是示例,所以尽可能的简单,我们先设计两张表:Order 和 Product

我们先写Entity Model,无论传统方式还是Fluent,都需要这个Model。

public class Product
{
    public virtual int ProductID { get; set; }

    public virtual string Name { get; set; }

    public virtual decimal Price { get; set; }

    public virtual DateTime CreateTime { get; set; }
}

public class Order
{
    public virtual int OrderID { get; set; }

    public virtual decimal Price { get; set; }

    public virtual OrderState State { get; set; }

    public virtual DateTime CreateTime { get; set; }
}

public enum OrderState
{
    Created,
    Paied,
    Consignment,
    Complete,
}

稍微简单介绍下,订单有订单号、总价、订单状态、创建时间等属性,状态现在是int类型,过后我演示一下如何使用枚举型。产品有产品ID,产品名,价格,创建时间。今天的内容不涉及关联关系,所以我们今天暂且不说Order。

好了,接下来开始我们的代码演示阶段。

传统方式:传统方式使用xml文件进行映射,配置文件如下:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="EntityModel" assembly="EntityModel">
  <class name="Product" table="Product">
    <id name="ProductID">
      <generator class="native" />
    </id>
    <property name="Name">
      <column name="Name" length="50" sql-type="varchar(50)" not-null="true" />
    </property>
    <property name="Price">
      <column name="Price" sql-type="real" not-null="true" />
    </property>
    <property name="CreateTime">
      <column name="CreateTime" sql-type="datetime" not-null="true" />
    </property>
  </class>
</hibernate-mapping>

Order的映射大体与Product相似。

Fluent方式:或许你会觉得我们用了配置文件进行映射,相当的简单,想怎么配就可以了,但实际用下来,我还是更喜欢Fluent的映射方式,映射代码如下:

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(m => m.ProductID);
        Map(m => m.Name);
        Map(m => m.Price).ColumnName("Price");
        Map(m => m.CreateTime);
    }
}

我们只需要继承Fluent的ClassMap<T>类,然后在构造方法中完成映射方法,就能完成传统方式的映射了。映射的方式很简单吧,相信大家都能看懂吧,为什么会如此方便呢?这其实就是完全靠了Lambda表达式,大家可以看看老赵的“从.NET框架中委托写法的演变谈开去”,就非常清楚了。我们来看看Id和Map

Id(Expression<Func<T, object>> expression):一看就很明白了,主键嘛,因为有了VS,因为有了泛型,因为有了委托,因为……,我们只需要简单的 m => m.ProductID,可能你会说主键的类型,主键还有很多特性,难道不需要配置吗?回答是当然需要,因为我们这里的属性名与表中的主键名是相同的,所以没有进行设置,如果你数据库的主键名是ID,这里我们只需要Id(m => m.ProductID).ColumnName(“ID”),你可以看到上述映射中的Price,我用了一下,其实不用也是没有关系的,只是做演示。当然还有很多,因为有了智能感知,我们只要.一下就能看到很多方法,但有一点你要注意,.ColumnName()后就不能再进行配置了,所以其他一些配置,你要放在ColumName之前。

Map(Expression<Func<T, object>> expression):与Id类似,对应NHibernate中的property,我这里只是简单的映射,还有很多特性,在今后的教程中会慢慢使用。

两者之间的对比,只有用了以后你才能懂得,只能意传不能言语。对于我这种新手来说,Fluent更适合我,因为我可以用它来进行学习NHibernate。

映射做好了,接下来我们在NHibernate中把映射加到配置中。

传统方式:

<mapping assembly="MyNHibernate"/>

Fluent:

private static ISessionFactory CreateSessionFactory()
{
    return Fluently.Configure()
       .Database(MsSqlConfiguration.MsSql2005
            .ConnectionString(s => s.Server(".")
                .Database("MyNHibernate")
                .TrustedConnection()))
        .
        .BuildSessionFactory();
}

Fluent的方式比上一篇中多了Mappings方法,Mappings的配置方式有很多,我这里用了最简单的FluentMappings.AddFromAssembly,只要添加Entity Mapping所在的程序集就可以了。当然还有更多的方法,如果大家想了解的话,可以看一下Fluent NHibernate API Document

在这里顺带介绍一下,MappingConfiguration.ExportTo(string path) 方法,它能把你的Entity Mapping自动生成hbm.xml文件到你指定的path中,我们可以生成好hbm.xml文件,自己再看一篇,看看NHibernate的映射方式,所以是非常好的一个方法,我有时候做映射的时候,遇到问题都会生成出来,随时查看问题所在,所以说是非常有用的一个方法,而且你可以把你的映射文件直接用到NHibernate项目中去。

Product我们映射好了,我们试着测试一下吧,这一次,我们用传统方式插入数据,用Fluent方式获取数据,测试代码如下:

[TestMethod]
public void NHibernateFactory()
{
    var factory = TradSessionFactory.GetCurrentFactory();
    using (ISession session = factory.OpenSession())
    {
        Product product = new Product();
        product.CreateTime = DateTime.Now;
        product.Name = "First Product";
        product.Price = 15;

        session.Save(product);
    }
}

[TestMethod]
public void FluentFactory()
{
    var factory = FluentSessionFactory.GetCurrentFactory();
    using (var session = factory.OpenSession())
    {
        Product product = session.Load<Product>(1);
        Assert.AreEqual("First Product", product.Name);
    }
}

如果我们的映射都正确,这2个单元测应该会都通过,接下来我们看下测试结果:

正如我们预料的一样,测试通过,说明我们的映射没有出现错误。

二、使用自定义类型映射实体属性

NHibernate支持我们用自定义的类型来映射属性,但因为我是初学,我真的不会,当然我在网上找到了相关的资料,在此也不多说,就说说Fluent的方式吧,在我映射自定义属性的时候,也就是Map()的时候,我想看看Map还有哪些方法,结果就看到了CustomTypeIs() 和 CustomTypeIs<T>() 两个方法,一个使用反射,一个用泛型,强类型,我当然会选择后者咯。为了接下来的方便,我把Fluent的Mapping都生成到我传统方式的Mapping目录中,加入到项目,设置成嵌入的资源,一切都为了以后的教程,换句话说以后的教程中,我一般都会使用Fluent来进行映射,而传统方式作为学习之用。

在Order实体中,我们看到了订单状态我用了OrderState枚举类型,数据库存储类型为tinyint,对于它的映射,我们只需要:

public class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        Id(p => p.OrderID);
        Map(p => p.Price);
        Map(p => p.State).CustomTypeIs<OrderState>();
        Map(p => p.CreateTime);
    }
}

是啊是啊,就这么简单,懂了吧,不需要解释了吧,连我英文这么差都能看得那么明白,我相信博客园的朋友一定比我更明白了吧。传统方式的映射,我是看了生成文件,也不是很复杂,而且我觉得生成的文件比我自己写的还要标准,呵呵。顺便贴一下吧。

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="">
  <class name="EntityModel.Order, EntityModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Order`" xmlns="urn:nhibernate-mapping-2.2">
    <id name="OrderID" type="Int32" column="OrderID">
      <generator class="identity" />
    </id>
    <property name="Price" type="Decimal">
      <column name="Price" />
    </property>
    <property name="State" type="EntityModel.OrderState, EntityModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <column name="State" />
    </property>
    <property name="CreateTime" type="DateTime">
      <column name="CreateTime" />
    </property>
  </class>
</hibernate-mapping>

接下来还是测试,这次换Fluent方式来新增Order,传统方式来获取这个Order,代码如下:

[TestMethod]
public void NHibernateFactory()
{
    var factory = TradSessionFactory.GetCurrentFactory();
    using (var session = factory.OpenSession())
    {
        Order order = session.Load<Order>(1);
        Assert.AreEqual(OrderState.Created, order.State);
        Assert.AreEqual(200, order.Price);
    }
}

[TestMethod]
public void FluentFactory()
{
    var factory = FluentSessionFactory.GetCurrentFactory();
    using (var session = factory.OpenSession())
    {
        Order order = new Order()
        {
            Price = 200,
            State = OrderState.Created,
            CreateTime = DateTime.Now
        };

        session.Save(order);
    }
}

老规矩,翠花,上测试结果:

不错不错,测试一切正常,今天的代码就到这里。

总结

今天介绍了如何映射简单的实体,但很多时候这都是理想的数据设计,还有更多复杂,不可预计的数据设计,这时候我们Fluent能做到吗?这个答案我也不知道,至少我在解决的问题的时候,觉得Fluent方式比传统方式要方便一些,至少我们测试的时候,我不需要把映射文件,配置文件等重新到复制到测试项目中了,呵呵。NHibernate是个强大的ORM框架,对他的了解我还太浅,还需要一定的时间去掌握。

前几天的开篇“Fluent NHibernate之旅一”,反响不是很好,或许大家用NHibernate的真的很少,或许我写的不够好,或许。。。。不过这不影响我需要完成这个系列的愿望,因为真的遇到了太多难以解决的问题,确实在解决中学到了很多,我很希望能把这一切与大家一起分享,至于好与坏,待大家来评价吧。

PS:终于可以上网了,憋了好久啊,哈哈

时间: 2024-10-20 09:46:55

[原创]Fluent NHibernate之旅二--Entity Mapping的相关文章

[原创]Fluent NHibernate之旅(四)-- 关系(上)

经过了前面三篇的介绍,相信大家对Fluent NHibernate已经有一定的了解了,在我们学习中,Fluent 也已经进入了RTM版本.这次的版本发布离RC版只有半个月不到,修正了很多bug,同时补充了大量的功能,在每天更新中,也看到了大量的单元测试,我们相信Fluent NHibernate 已经相对稳定成熟了.RTM相对于RC版本来说,使用方法没有太大的变化,所以不做讲解. 我们后面的教程,会使用RTM版本来演示,希望大家能及时更新(点击下载最新版). Fluent NHibernate之

[原创]Fluent NHibernate之旅(四)-- 关系(中)

接着上一篇,我们继续讲解ORM中的关系.在数据库设计中,我们最多打交道的,要算一对多关系了,延续我们的示例,我们来讲解一下一对多的关系. Fluent NHibernate之旅系列导航: 一.开篇:ISessionFactory Configuration 二.实体映射:Entity Mapping 三.继承映射:Inheritence Mapping 四.一对一映射:One-to-One Mapping 场景和数据库设计 延续我们的演示范例,用户和订单是非常典型的一对多范例. 1.一个用户可以

[原创]Fluent NHibernate之旅

ORM大家都非常熟悉了吧,我相信也有很多朋友正在用自己或者一些公开的框架,而最常用而且强大的,非Hibernate了(Net中为NHibernate),网上的文档非常多,不过在博客园中,介绍NHibernate的非常少,李哥的NHibernate系列(NHibernate之旅)不失为一个经典,对于新手的我们,需要完全掌握还需要很长一段路,对于新手来说,最初的配置是非常头大的一件事情,好在老赵推荐一个开源的框架Fluent NHibernate,有了它,我们可以完全脱离配置文件,不过博客园中介绍F

[原创]Fluent NHibernate之旅(四)-- 关系(下)

最近一直忙着准备去旅行的东东,所以进度慢下来了,明天就要出发了,嘿嘿,在出发前,把多对多给写完吧.如果你第一次看这个系列,可以先看看先前几篇,了解下. 一.开篇:ISessionFactory Configuration 二.实体映射:Entity Mapping 三.继承映射:Inheritence Mapping 四.一对一映射:One-to-One Mapping 五.一对多映射:One-to-Many Mapping 场景和数据库设计 前两篇我们介绍了"一对一"和"一

[原创]Fluent NHibernate之旅(三)-- 继承

经过了"开篇"和"简单映射"两篇文章,相信大家对Fluent NHibernate 有了一定的了解了,FluentNHibernate实际就是对 NHibernate 映射的一定扩展,我们能完全利用强类型.泛型.Lambde表达式等等Vs.Framework等特性简单完成映射工作,同时也能让我们学习NHibernate的映射方式,一举夺得,这么好玩的东东,有理由不继续完成这个系列吗?废话不说,回到正题. 从这一篇开始,我们将使用Fluent NHibernate R

Fluent NHibernate 之旅 导航篇

ORM大家都非常熟悉了吧,我相信也有很多朋友正在用自己或者一些公开的框架,而最常用而且强大的,非Hibernate了(Net中为NHibernate),网上的文档非常多,不过在博客园中,介绍NHibernate的非常少,李哥的NHibernate系列(NHibernate之旅)不失为一个经典,对于新手的我们,需要完全掌握还需要很长一段路,对于新手来说,最初的配置是非常头大的一件事情,好在老赵推荐一个开源的框架Fluent NHibernate,有了它,我们可以完全脱离配置文件,不过博客园中介绍F

Fluent Nhibernate之旅(五)--利用AutoMapping进行简单开发

Fluent Nhibernate(以下简称FN)发展到如今,已经相当成熟了,在Nhibernate的书中也相应的推荐了使用FN来进行映射配置,之前写的FN之旅至今还有很多人会来私信我问题,说来惭愧,从FN之旅四至今已经4年多,至今还未更新过此系列,原因有很多,最大的就是懒惰,哈. 安装 现在在项目中使用FN很方便,使用Nuget管理就可以了,但我还是建议大家,可以下载源代码,自己可以详细了解下. 当然,您也可以用命令台来进行安装.说个题外话,NuGet真心不错,至少已经做新项目的时候不用到处去

[Fluent NHibernate]一对多关系处理

目录 写在前面 系列文章 一对多关系 总结 写在前面 上篇文章简单介绍了,Fluent Nhibernate使用代码的方式生成Nhibernate的配置文件,以及如何生成持久化类的映射文件.通过上篇的学习你会发现,Fluent Nhibernate仍然需要引用Nhibernate的两个程序集(Nhibernate.dll和Iesi.Collections.dll),所以与Nhibernate最大的区别就在生成配置文件的方式上面,这里关于Nhibernate的特性方面就不再多赘述,可以参考Nhib

如何使用Fluent Nhibernate中的Automapping进行OR Mapping映射

由于在项目中使用了NHibernate来作为ORMapping构建数据访问层,那么就必须要配置Object和DataTable的映射.最早的项目中,我们使用了最传统的XML配置文件的方式编写映射关系,但是这样太麻烦,每次修改class和表时都要去修改对应的XML文件,而且还容易出错,一定有疏忽遗漏的地方,还不容易找出错误,所以在第二个项目中,我们使用了Fluent NHibernate的Mapping方式代替XML配置.使用Fluent NHibernate的最大好处是降低了出错的机会,因为Fl