前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >[原创]Fluent NHibernate之旅(四)-- 关系(上)

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

作者头像
脑洞的蜂蜜
发布于 2018-02-02 06:55:14
发布于 2018-02-02 06:55:14
1.2K00
代码可运行
举报
文章被收录于专栏:NetCoreNetCore
运行总次数:0
代码可运行

经过了前面三篇的介绍,相信大家对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是一对一关系,构建我们的实体类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 映射代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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").GeneratedBy.Foreign("User");
        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",代表的是无论什么操作,都会同时操作关联对象。

映射完,我们测试一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[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,或许你会说,使用以下方式来进行延迟加载:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HasOne<UserDetail>(u => u.Detail).Cascade.All().LazyLoad();

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HasOne<UserDetail>(u => u.Detail).Cascade.All().Fetch.Select();
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HasOne<User>(d => d.User).Cascade.All().Constrained();

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

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

总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2009-09-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
微信消息推送神器pushplus介绍,让消息推送如此简单
原生实现微信消息推送需要申请公众号、成为开发者,实现微信公众号接入和消息推送等接口。
杨永贞
2022/10/25
12.2K0
微信消息推送神器pushplus介绍,让消息推送如此简单
消息推送平台的设计
第一点:导入消息接收人的数据可以支持excel导入,然后去各个业务线去拉取完整的用户id即可,导入的数据需要分页提交给服务或者分页落库
花落花相惜
2021/11/23
2.5K0
小程序消息推送x微搭低代码,微信消息推送快速上手实操教程
近期有很多同学关注小程序消息推送的问题,今天就简单介绍下微搭低代码开发的小程序应用如何实现微信订阅消息的推送,目前方案有两种:
漫话开发者
2023/01/02
2K0
小程序消息推送x微搭低代码,微信消息推送快速上手实操教程
揭秘!消息管理平台的实现原理
这个系列就以「消息管理平台」来打个样吧,这是我维护近一年的系统了。这篇文章可以带你全面认识「消息管理平台」是怎么设计和实现的,有兴趣的同学欢迎在评论区下留言和交流。
Java3y
2020/09/24
1.6K0
揭秘!消息管理平台的实现原理
【随笔】自动化油价推送:GitHub Actions 实战
在网上找到一个油价网站,http://www.qiyoujiage.com , 定位到自己所在的具体地址,例如:http://www.qiyoujiage.com/hubei/xxx.shtml ,通过 jsoup 抓取关键数据,如 92#-0# 汽油价格等其他自己需要的数据。
框架师
2023/12/16
2070
【随笔】自动化油价推送:GitHub Actions 实战
Spug推送平台:开发者的消息推送神器
外滩首席运维
2025/02/25
1120
Austin消息中心
写这篇文章是首先我之前也是做过消息中心的需求,当时3y开源了它的项目Austin,当时觉得挺好的,之后我负责的消息中心重构了一版,现在想想也挺开心的。所以想把之前学习的整理了下来。
路行的亚洲
2023/08/31
9730
Austin消息中心
带你了解什么是Push消息推送
而Push消息是这么多种类型之中非常重要和常用的一种类型,最近也希望针对Push推送做些新的尝试,于是去学习学习些Push消息运营的技巧。
Java3y
2019/08/29
2.6K0
带你了解什么是Push消息推送
喜马拉雅亿级用户量的离线消息推送系统架构设计实践
对于IM的开发者来说,离线消息推送是再熟悉不过的需求了,比如下图就是典型的IM离线消息通知效果。
JackJiang
2021/07/14
1.4K0
喜马拉雅亿级用户量的离线消息推送系统架构设计实践
Android消息推送:手把手教你集成小米推送
继承自PushMessageReceiver(抽象类,继承自BroadcastReceiver),其作用主要是:
Carson.Ho
2019/02/22
4.7K0
消息推送技术,除了websocket还知道那些?
WebSocket是一种网络通信协议,它提供了在单个TCP连接上进行全双工通信的能力。这意味着数据可以在客户端和服务器之间双向流动,而无需客户端通过轮询或重复请求来获取更新。
老K博客
2024/06/01
7120
消息推送技术,除了websocket还知道那些?
移动端开发之APP消息推送[通俗易懂]
有这样一种场景,当你在手机APP上输入你的信息,会自动跳出一个弹窗,表示某任务已执行。最简单的一个例子就是当你输入手机号,点击获取验证码的时候,就会跳出一个对话框,说“验证码已发送到手机,请注意查收”,这些都是如何实现的。
全栈程序员站长
2022/09/05
3.6K0
移动端开发之APP消息推送[通俗易懂]
如何构建一套高可用的移动消息推送平台?
消息推送作为移动 APP 运营中的一项关键技术,已经被越来越广泛的运用。本文追溯了推送技术的发展历史,剖析了其核心原理,并对推送服务的关键技术进行深入剖析,围绕消息推送时产生的服务不稳定性,消息丢失、延迟,接入复杂性,统计缺失等问题,提供了一整套平台级的高可用消息推送解决方案。实践中,借助于该平台,不仅能提能显著提高消息到达率,还能提高研发效率,并道出了移动开发基础设施的平台化架构思路。
Java3y
2019/09/12
3.2K0
如何构建一套高可用的移动消息推送平台?
微信小程序之订阅消息推送java开发
2019年10月份微信发布了模板消息整改公告由模板消息更改为订阅消息: 具体公告地址:https://developers.weixin.qq.com/community/develop/doc/
猿码优创
2020/06/12
5.1K0
喜马拉雅亿级用户量的离线消息推送系统架构设计实践
对于IM的开发者来说,离线消息推送是再熟悉不过的需求了,比如下图就是典型的IM离线消息通知效果。
JackJiang
2021/07/12
1.1K0
SignalR 中丰富多彩的消息推送方式
在上一篇 SignalR 文章中,演示了如何通过 SignalR 实现了简单的聊天室功能;本着简洁就是美的原则,这一篇我们也来聊聊在 SignalR 中的用户和组的概念,理解这些基础知识有助于更好的开发基于 SignalR 的应用,通过对用户和分组的理解,进一步扩展出对用户和分组的管理,以及消息推送的各种方式,为全面接入 SignalR 做准备。
梁规晓
2019/04/11
1K0
SignalR 中丰富多彩的消息推送方式
小程序消息推送,订阅消息的实现,借助云开发云函数实现定时推送订阅消息功能
由于长期性订阅消息,目前仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。仅就线下公共服务这一点,长期性订阅消息就和大部分开发者无缘了。 所以我们这里只能以使用一次性订阅消息为例。
编程小石头
2022/03/18
2.6K0
小程序消息推送,订阅消息的实现,借助云开发云函数实现定时推送订阅消息功能
小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送
至于如何创建模板消息,如果获取模板id我这节就不再讲解,不知道的同学可以查看我上篇文章《借助云开发实现小程序订阅消息和模板消息的推送功能》里面有详细的讲解。
编程小石头
2020/01/05
4.9K0
小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送
Java点餐系统和点餐小程序新加微信消息推送功能
我们今天就以排号入座为例,当排号等位的用户被叫号时,会给用户发送一条微信订阅消息。就是在管理点击下图的可入座时,发送订阅消息给用户。
编程小石头
2020/10/11
2.1K0
Hutool该怎么用?
在日常开发中,我们会使用很多工具类来提升项目开发的速度,而国内用的比较多的 Hutool 框架,就是其中之一。
程序猿川子
2024/05/21
2580
Hutool该怎么用?
推荐阅读
相关推荐
微信消息推送神器pushplus介绍,让消息推送如此简单
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文