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

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

我们后面的教程,会使用RTM版本来演示,希望大家能及时更新(点击下载最新版)。

Fluent NHibernate之旅系列导航:

一、开篇:ISessionFactory Configuration

二、实体映射:Entity Mapping

三、继承映射:Inheritence Mapping

今天我们将说一下ORM中的R映射,我们现在的数据库大多都是关系型数据库了,所以可以说关系在我们数据库设计中也是非常重要的部分,NHibernate也非常重视这一块,但在传统方式中,配置就比较麻烦,不是说我们Fluent能简单,只是传统方式的xml看上去不太美观,而Fluent这种代码式方式,更能符合我们Developer的习惯。

数据库关系

数据库关系一般有:

1、一对一

2、一对多

3、多对多

开始

结合我们前三个系列的示例,我们这一次加一个用户表[User],目的就是存储用户信息所用,再加一个UserDetail,作为用户的详细信息。怎么简单怎么来,数据库设计如下:

够简单的吧,User和UserDetail是一对一关系,构建我们的实体类:

public class User
{
    public virtual int UserID { get; set; }

    public virtual string UserName { get; set; }

    public virtual string Password { get; set; }

    public virtual DateTime CreateTime { get; set; }

    public virtual UserDetail Detail { get; set; }
}

public class UserDetail
{
    public virtual User User { get; set; }

    public virtual int UserID { get; set; }

    public virtual DateTime LastUpdated { get; set; }

    public virtual PersonName Name { get; set; }
}

public class PersonName
{
    public virtual string FirstName { get; set; }

    public virtual string LastName { get; set; }
}

嘿,为什么是三个model呢,因为我发现前几个系列里,没有说一下Component Mapping,所以今天一并说了。这是我们简单的一个一对一的设计,我们先只要求实现映射,至于其他的比如延迟加载的,稍后说。先跑起来溜溜。

映射

Fluent NHibernate 映射代码:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(u => u.UserID).GeneratedBy.Identity() ;
        Map(u => u.UserName);
        Map(u => u.Password);
        Map(u => u.CreateTime);
        HasOne<UserDetail>(u => u.Detail).Cascade.All().PropertyRef("User");
    }
}

public class UserDetailMap : ClassMap<UserDetail>
{
    public UserDetailMap()
    {
        Id(u => u.UserID).Column("UserID").;
        HasOne<User>(d => d.User).Cascade.All().Constrained();
        Map(u => u.LastUpdated).Nullable();
        Component<PersonName>(u => u.Name, p =>
        {
            p.Map(o => o.FirstName).Column("[First Name]");
            p.Map(o => o.LastName).Column("[Last Name]");
        });
    }
}

代码中有几点要注意(红色标记):因为UserDetail使用的主键ID与User的ID是一致的,所以我们要使用Foregin来获取User的ID。Foreign的用法与先前版本有一点不同,需要指定propertyName。很多关联方法都是与NHibernate很类似的,比如Cascade,Cascade.All代表的是cascade="all",代表的是无论什么操作,都会同时操作关联对象。

映射完,我们测试一下:

[Fact]
public void CreateUserTest()
{
    var factory = FluentSessionFactory.GetCurrentFactory();
    using (var session = factory.OpenSession())
    {
        DateTime createTime = DateTime.ParseExact("2009-07-08 11:00", "yyyy-MM-dd hh:ss",null);
        User user = new User()
        {
            CreateTime = createTime,
            Password = "ilovecandy",
            UserName = "james",
        };

        UserDetail detail = new UserDetail
        {
            Name = new PersonName { FirstName = "James", LastName = "Ying" },
            LastUpdated = createTime,
        };

        detail.User = user;
        user.Detail = detail;

        session.Save(user);
        session.Flush();
    }
}

[Fact]
public void SelectUserTest()
{
     var factory = FluentSessionFactory.GetCurrentFactory();
     using (var session = factory.OpenSession())
     {
         User user = session.Get<User>(1);
         Assert.Equal("James", user.Detail.Name.FirstName);
     }
}

从这篇以后,单元测试会使用Xunit,可以点此下载

一个插入测试,一个查询测试,看看测试结果:

output:

ok,测试通过。我们的一对一简单映射也说完了,同时也完成了Component的映射,接下来说说延迟加载

一对一延迟加载

细心的朋友一定会发现我们的output出来的Sql语句,使用的是联合查询,但有时对我们来说,只需要User就可以了,我不需要查询UserDetail,或许你会说,使用以下方式来进行延迟加载:

HasOne<UserDetail>(u => u.Detail).Cascade.All().LazyLoad();

虽然Fluent支持,虽然编译通过,但在创建ISessionFactory的时候,却会抛出异常,因为NHibernate不支持one-to-one的Lazy的特性,也就是说NHibernate不支持一对一的延迟加载。但是查了很多资料,说可以用:

HasOne<UserDetail>(u => u.Detail).Cascade.All().Fetch.Select();
HasOne<User>(d => d.User).Cascade.All().Constrained();

进行延迟加载,但结果只是分了2条Sql语句进行的查询,并不是延迟加载,这一点可以通过Sql Server Profiler查看:

NHibernate是不支持one-to-one的延迟加载的,我也不知道为什么,但我们可以婉转的进行延迟加载,老赵已经在他的文章“NHibernate中一对一关联的延迟加载”中提出了解决方案,大家可以看一下。

总结

因为关联在数据中属于比较重要的一部分,所以准备拆分成上中下进行讲解。今天说了关联中比较简单的一对一关系,其实一对一关系并不简单,第一次接触的时候,难免会遇到各种问题,很欢迎大家能留言,大家一起讨论问题。

时间: 2024-11-05 17:27:53

[原创]Fluent NHibernate之旅(四)-- 关系(上)的相关文章

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

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

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

接着上一篇,今天我们说说ORM中的Mapping.如果你要体验NHibernate的强大,首先你就要学会配置,包括SessionFactory和Mapping的配置.今天跟上一篇一样,会使用传统方式和 NHibernate 进行讲解.如果你要亲手试验一下,可以先看一下"Fluent NHibernate之旅一",进行一下数据库和SessionFactory的准备. 本节内容: 简单实体映射 使用自定义类型映射实体属性 NHibernate的实体映射(Entity Mapping)做的非

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

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

[原创]Fluent NHibernate之旅

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

[原创]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

NHibernate之旅(23):探索NHibernate二级缓存(上)

本节内容 引入 介绍NHibernate二级缓存 NHibernate二级缓存提供程序 实现NHibernate二级缓存 结语 引入 上一篇我介绍了NHibernate内置的一级缓存即ISession缓存.这篇我们来了解下NHibernate二级缓存即ISessionFactory级别缓存.二级缓存是可扩展的,在NHibernate Contrib上提供了第三方NHibernate二级缓存提供程序. 介绍NHibernate二级缓存 NHibernate二级缓存由ISessionFactory创