PetaPOCO 一对多 多对一 多对多
PetaPoco支持将结果集中的一行映射到到两个以及更多POCO,但是如何处理一对多和多对多关系?
1、PetaPoco 支持将结果映射为多个POCO类型,提供了另一种方法来处理SQL的Join查询。
背景
多POCO查询背后的想法是生成一个SQL JOIN查询,并将每个表返回的列自动的映射给POCO表示。换句话说,不是一行被映射为一个POCO,前N列被映射到一个POCO,后N列的映射给另一个,等等..
示例:
var sql = PetaPoco.Sql.Builder
.Append("SELECT articles.*, authors.*")
.Append("FROM articles")
.Append("LEFT JOIN users ON articles.user_id = users.user_id"); var result = db.Query<article, user, article>( (a,u)=>{a.user=u; return a }, sql);
注意事项:
- SQL查询的结果返回自两个表中.
- 前两个泛型参数类型指定了查询时每行数据中包含数据的POCO类型.
- 第三泛型参数是返回集类型- 一般与第一个表类型相同,但也可能为其他类型.
- 查询方法将它的第一个参数作为一个回调委托,可用来连接两个对象的关系.
在这个例子中,我们返回了一个IEnumerable<article> ,其中每个article对象都有一个通过user属性对与之相关user的引用.
选择分割点
支持多POCO查询的本质就是确定返回的结果集应如何分割。如:那些列映射到那些POCO上。返回列必须和在Query<>中传递的泛型参数顺序相同。如:前N列映射给T1,后N列映射给T2.等等....从返回结果的最左边的列开始将其映射给第一个POCO。搜索一个分割点并顺序的将后续的列映射给下一个POCO类型。
如果一个列名已经映射到当前的POCO类型,就认为它是一个分割点。思考这个序列:
article_id, title, content, user_id, user_id, name
//POCOs:
class article
{
long article_id { get; set; }
string title { get; set; }
string content { get; set; }
long user_id { get; set; }
} class user
{
long user_id { get; set; }
string name { get; set; }
} //Query
db.Query<article, user, article>( ... )
这里我们关注的是use_id,在映射结果集时,第一个user_id列将被映射给article Poco。当看到第二个user_id列时,PetaPoco会意识到它已经映射给了articles 属性并开始将之映射给user Poco。分割点最后的处理方法是确定当前POCO类型中不存在某一列但存下一个POCO中存在。注意如果一个列不在当前的POCO类型中也不在下一个POCO中,那么它将被忽略。
自动连接 POCO's
PetaPoco 也可以猜出属性关系并返回的对象的引用赋值给它。
比如:
var result = db.Query<article, user, article>( (a,u)=>{a.user=u; return a }, sql);
可以简单的写成:
var result = db.Query<article, user>(sql);
这里有两点需要注意:
- 不需要指定返回类型参数(第三个参数).返回集将永远是类型
T1. - 用于设置对象关系的回调函数也不需要.
很明显,这个是通过PetaPoco来猜测工作的,且在通常大多数情况 是值得的。要使其起作用,T2到T5必须有一个与他左侧类型相同的属性类型。换句话说:
T1必须具有T2的一个属性T1或T2必须具有T3的一个属性T1或T2或T3 必须具备类型T4的一个属性- 等等...
再者,属性是从右至左进行查找的,所以如果T2和T3都具备类型T4的一个属性, T3的属性将被使用.
2、一对多和多对一
实例标识和废弃的POCO
"Instance Identity"的准确含义是什么? 我的意思是如果一条特定的记录在两个或者更多的地方在所有的情况下从查询返回相同的POCO实例,或者POCO实例唯一标识该记录。例如,假设你正在做一个文章表和作者表的Join查询,如果两篇文章,作者是相同的,那么都将引用同一作者的对象实例。
PetaPoco的多POCO查询一直为每一行数据创建一个POCO实例.所以在上面的例子中,每行都将创建一个新的作者对象.为了正确的得到实例标识,我们将最终丢弃重复值。所以不要把一对多和多对一映射当成是一个改善效率的方法,只在更多准确的对象映射对你有用是使用。
责任方式回调
在创建行个人POCOs所谓的“责任方式回调”,其工作是连接对象为该行成一个对象图。这个最简单的方法是简单地分配在LHS对象的一个属性的RHS对象。这是什么PetaPoco的自动映射。这是一个简单而快速的方法,但它并没有提供我们谈论的对象标识。
自动映射和简单关系
在我们涉及责任方式回调前,让我们看看一个简单的自动映射多POCO查询:
var posts = db.Fetch<post, author>(@"
SELECT * FROM posts
LEFT JOIN authors ON posts.author = authors.id ORDER BY posts.id
");
使用自动映射,第一个泛型参数为返回类型.所以这个例子将返回一个List<post>,所以只要post对象有author对象的一个属性,PetaPoco将进行连接并创建author对象.
责任方式回调:
var posts = db.Fetch<post, author, post>(
(p,a)=> { p.author_obj = a; return p; },
@"SELECT * FROM posts
LEFT JOIN authors ON posts.author = authors.id ORDER BY posts.id
");
注意以下两点:
这里有一个额外的泛型参数组-<post, author, post>.最后一个参数指示了返回集合元素的类型。使用一个自定义的relator,你也许决定使用不同的类来描述连接行。
lambda函数用来连接post和author.
- 多对一关系
为了实现多对一关系,所有我们需要做的就是保持一个映射对应的对象并重复使用.(多对一,因为很多行可能同时对应于一个对象,只需将对应的对象保存下来,并每次重复使用之生成映射关系)
//用于保存为一的authors
var authors = new Dictionary<long, author>();
var posts = db.Fetch<post, author, post>(
(p, a) =>
{
//获取存在的author对象
author aExisting;
//如果author已经存在
if (authors.TryGetValue(a.id, out aExisting))
a = aExisting;
else
authors.Add(a.id, a); //连接对象
p.author_obj = a;
return p;
},
"SELECT * FROM posts LEFT JOIN authors ON posts.author = authors.id ORDER BY posts.id"
);
如果需要在多个地方使用,可将之封装起来:
class PostAuthorRelator
{
//已知作者的字典集合
Dictionary<long, author> authors = new Dictionary<long, author>(); public post MapIt(post p, author a)
{
// 尝试获取已知的对象, 如果不存在则保存当前
author aExisting;
if (authors.TryGetValue(a.id, out aExisting))
a = aExisting;
else
authors.Add(a.id, a); // 连接对象
p.author_obj = a;
return p;
}
}
//使用方法
var posts = db.Fetch<post, author, post>(
new PostAuthorRelator().MapIt,
"SELECT * FROM posts LEFT JOIN authors ON posts.author = authors.id ORDER BY posts.id"
);
- 一对多关系
在一对多关系中,我们想要从右侧集合中将每个左侧对象组合为一个对象的集合。翻开我们上面的例子,我们想要一个作者的列表,每个作者都有一个该作者文章的集合:
SELECT * FROM authors
LEFT JOIN posts ON posts.author = authors.id ORDER BY posts.id
左边的作者需要合并成一个POCO, 每个作者右边的文章需要整合成一个列表.
为了支持这个,Petapoco允许一个责任回调返回Null来表示没有为当前记录提供,为了去掉最终的记录,
class AuthorPostRelator
{
public author current;
public author MapIt(author a, post p)
{
// 终止调用.因为我们可以从本函数返回null
//我们需要为后续使用null回调做好准备
// parameters
if (a == null)
return current; // 是否当前的作者与我们正在处理的相同
if (current != null && current.id == a.id)
{
// Yes,
current.posts.Add(p); //返回null表示我们已经处理完当前作者
return null;
} // 这是作者与当前处理的不同,或者是第一次处理,之前还未处理过 // 保存当前作者
var prev = current; // 设置新的当前作者
current = a;
current.posts = new List<post>();
current.posts.Add(p); // Return the now populated previous author (or null if first time through)
return prev;
}
}
var authors = db.Fetch<author, post, author>(
new AuthorPostRelator().MapIt,
"SELECT * FROM authors LEFT JOIN posts ON posts.author = authors.id ORDER BY posts.id"
);
So let's look at a one-to-many relator:
PetaPOCO 一对多 多对一 多对多的更多相关文章
- 【Jpa hibernate】一对多@OneToMany,多对一@ManyToOne的使用
项目中使用实体之间存在一对多@OneToMany,多对一@ManyToOne的映射关系,怎么设置呢? GitHub地址:https://github.com/AngelSXD/myagenorderd ...
- django 中models表的多对一,多对多的理解
django 表的理解 好处:设计的好,会清晰,易于理解和维护,后期开发事半功倍,一目了然. 1. 一对一的表,两表的属性实际上完全可以合并成一个表,共用一个主键即可: 2. 一对多的表,可以设中间关 ...
- flask的orm框架(SQLAlchemy)-一对多查询以及多对多查询
一对多,多对多是什么? 一对多.例如,班级与学生,一个班级对应多个学生,或者多个学生对应一个班级. 多对多.例如,学生与课程,可以有多个学生修同一门课,同时,一门课也有很多学生. 一对多查询 如果一个 ...
- mybatis 一对多,(多对一,一对一
多对一,和一对一是同一种写法,每种写法又分在数据库关联和在mybatis关联 1,多对一,一对一数据库关联 2,多对一,一对一mybatis关联 3,一对多,数据库关联,注意,Java type改of ...
- JDBC上关于数据库中多表操作一对多关系和多对多关系的实现方法
黑马程序员 我们知道,在设计一个Javabean的时候,要把这些BEAN 的数据存放在数据库中的表结构,然而这些数据库中的表直接又有些特殊的关系,例如员工与部门直接有一对多的关系,学生与老师直接又多对 ...
- Hibernate双向一对多、双向多对多关联关系中的映射文件怎么写
这里以一对多关联关系为例.以Country类为一端,Competition类为多端. 一个国家可以有多个赛事,但是一个赛事只能属于一个国家. Country类 public class Country ...
- PringData JPA一对多多对一多对多关联
一.一对多.多对一 1.Country实体类 2.City实体类 3.CountryDao层 4.CityDao层 5.Controller package com.zn.controller; im ...
- SpringData JPA一对多多对一多对多关联
一.一对多.多对一 1.Country实体类 2.City实体类 3.CountryDao层 4.CityDao层 5.Controller package com.zn.controller; im ...
- spring-data-jpa一对多多对一多对多关联
一对多.多对一 Country类 @Entity @Table(name = "Country") public class Country { @Id //sequence id ...
随机推荐
- Codeforces 710 E. Generate a String (dp)
题目链接:http://codeforces.com/problemset/problem/710/E 加或者减一个字符代价为x,字符数量翻倍代价为y,初始空字符,问你到n个字符的最小代价是多少. d ...
- 使用多个Worker的时候Odoo的系统日志配置
当我们开启Wokrer来启动Odoo的时候,用默认的日志会出现日志丢失的问题,这个是logger的问题:多个进程对单个文件写入日志.有一个简单的解决办法:配置openerp-server.conf,开 ...
- chrome浏览器下用jQuery的load函数来跨域加载页面,响应状态status为(canceled)是什么情况? JSON和JSONP,也许你会豁然开朗,含jQuery用例
http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 问题来源:http://q.cnblogs.com ...
- 全代码实现ios-1
第一次接触ios开发时,就决定用代码开发,而不用ib.因为被ib的各种控件的联线弄得一头雾水,而且ib和storyboard变动太快了. 开始的时候真是麻烦,因为网上关于全代码开发的例子太少了,大多数 ...
- Thread message loop for a thread with a hidden window? Make AllocateHwnd safe
Thread message loop for a thread with a hidden window? I have a Delphi 6 application that has a thre ...
- AC、HC、AHC、ACT、LS的区别
http://forum.eet-cn.com/thread!printPreview.jspa?threadID=1200029698&start=0 以245为例,74AC245.74HC ...
- SAE J1850 VPW PWM, SAE J2411 SWC, ISO 11898 CAN, SAE J1708, Chrysler CCD 接口芯片电路
SAE J1850 VPW 接口芯片电路 SAE J1850 PWM 接口芯片电路 SAE J2411 SWC 接口芯片电路 ISO 11898 CAN 接口芯片电路 CANH 和CANL 上的电容 ...
- PL/pgSQL RETURNS TABLE 例子
实验如下: RETURNS TABLE 中的变量名和SQL文中的变量名同名时,执行时会出错: pgsql=# create table sales(itemno integer,quantity in ...
- [Unity3D]Unity3D游戏开发之在3D场景中选择物体并显示轮廓效果
大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 在<仙剑奇侠传>.<古剑奇谭>等游戏中,常常须要玩家在一个3D场景中 ...
- JQueryMobile页面跳转参数的传递解决方案
在JQueryMobile开发手机端应用使用可能需要考虑相关的页面跳转带来的参数问题.因为JQueryMobile其实也是HTML5实践的结果.HTML5中有localStorage和sessionS ...