MyBatis-Plus不寫任何resultMap和SQL執行一對一、一對多、多對多關聯查詢


對於一對一,一對多,多對一,多對多的關聯查詢,Mybatis-Plus 在處理時,需要編寫關聯查詢方法及配置resultMap,並且書寫SQL。

為了簡化這種操作,可以注解來簡化。

 

Mybatis-Plus-Relation  ( mprelation ) : mybatis-plus 一對一、一對多、多對一、多對多的自動關聯查詢,注解方式。

 

 交流QQ群: 1085077558

 

mprelation源碼地址  :

     github:     https://github.com/dreamyoung/mprelation.git   

     gitee:        https://gitee.com/dreamyoung/mprelation.git

mprelation_demo 地址  :

    github:      https://github.com/dreamyoung/mprelation_demo.git 

    gitee:        https://gitee.com/dreamyoung/mprelation_demo.git

 

POM引用 :

<dependency> <groupId>com.github.dreamyoung</groupId> <artifactId>mprelation</artifactId> <version>0.0.3.2-RELEASE</version> </dependency>

 

 

注解工具使用優缺點:

優點:

       使用簡單,通過在實體類上添加@OneToOne / @OneToMany@ManyToOne@ManyToMany  等注解即可。

       注解命名參考了Hibernate命名,如果使用過Hibernate則即刻可上手。

       1對1、1對多、多對1、多對多映射時,可以不再寫SQL及XML配置文件,免去配置冗長的<resultMap>的麻煩。

       Service層及Mapper層不需要再添加 getLinkById 、 selectLinkById   之類的方法來關聯映射

       重寫過的ServiceImpl各種內置的查詢方法都自動關聯查詢,非內置方法可以調用autoMapper相關方法進行自動或手動關聯

       所有執行采用非join方式查詢,同時解決關聯處理的1+n問題

缺點:

       目前只針對SqlSession/Mappe形式有效(ActiveRecord形式暫未涉及修改,也沒有測試)

       非事務下, 1個連接(1個SqlSession)只執行一條SQL,而自動獲取每個關聯屬性的sql都會創建1~2個SqlSession(並執行1~2條SQL)。如果需要使用非內置方法(即除ServiceImpl外的方法),必須配置只讀事務來減少SqlSession創建。

       如果有多個延遲加載的關聯屬性,類上可注解@AutoLazy(false)或沒有標注該注解(默認),之后通過initialize方法在事務范圍內的一個SqlSession中同時加載需要的多個延遲加載的屬性。

 

使用注意點:

       非ServiceImpl內置的業務查詢,配置事務管理,減少SqlSession的創建。

       實體上可用注解@AutoLazy(true/false)來標注是否自動觸發延遲加載,該注解只針對需要延遲的屬性。

               ★  true或無值的話,則獲取延遲的關聯屬性時自動關聯。但每一個延遲屬性的獲取都消耗一個SqlSession。適合於只有一個延遲屬性的情況。

               ★  false或者不標注該注解的話,需要手動通過initialize()方法對延遲的關聯屬性進行獲取,否則不會自動關聯獲取,此時關聯為空。適合於有多個延遲屬性的情況。

       如果可以,不使用延遲加載(延遲加載的使用是在SqlSession關閉后執行的,需要重新創建SqlSession)。

       如果確實需要延遲加載,可使用ServiceImpl   AutoMapper 相關的initialize方法一次性加載所有需要的被延遲的屬性(只需要創建額外的一個SqlSession,畢竟SqlSession之前已經關閉)

 

 

 

 

注解使用:

 

 一對多(多對一) :

Company實體類中配置:

@Data public class Company { @TableId(value = "company_id") private Long id; private String name; //一對多
    @TableField(exist = false) @OneToMany //一對多默認為延遲加載,即@Lazy/@Lazy(true)/或此時不標注 @JoinColumn(name="company_id",referencedColumnName = "company_id")//@TableId與一方相關屬性中@TableField名稱保持一致時@JoinColumn可省略  private Set<Man> employees; }

 

 Man實體類中配置:

@Data public class Man { @TableId(value = "man_id") private Long id; private String name;

//多對一 @TableField("company_id") private Long companyId; @TableField(exist = false) @ManyToOne //多對一默認為立即加載,即@Lazy(false)或此時不標注 @JoinColumn(name = "company_id", referencedColumnName = "company_id") //相關的@TableField與多方的@TableId名稱一致時@JoinColumn可省略 private Company company; }

 一對多(多對一)表結構:  company: (compnay_id,   name)           man: (man_id,    name,   company_id)

 

 

一對一:

Woman實體類配置:

@Data public class Woman { @TableId(value = "woman_id") private Long id; private String name; 
//一對一
@TableField("lao_gong_id")
private Long laoGongId; @TableField(exist = false) @OneToOne //一對一默認為立即加載,即@Lazy(false)或此時不標注 @JoinColumn(name = "lao_gong_id", referencedColumnName = "man_id")
private Man laoGong; }

 

Man實體類配置:

@Data public class Man { @TableId(value = "man_id") private Long id; private String name; //一對一
@TableField("lao_po_id") private Long laoPoId; @TableField(exist = false) @OneToOne @JoinColumn(name = "lao_po_id", referencedColumnName = "woman_id") private Woman laoPo; }

 一對一表結構:(實際可以減少一方)  woman: (woman_id,  name,   lao_gong_id)           man: (man_id,   name,   lao_po_id)

  

 

多對多:

Course實體類配置:

@Data public class Course { @TableId(value = "course_id") private Long id; private String name; //多對多
    @TableField(exist = false) @ManyToMany //多對多默認為延遲加載,即@Lazy(true)或此時不標注 @JoinTable(targetMapper = StudentCourseMapper.class) //第三方命名為StudentCourseMapper或CourseStudentMapper時@JoinTable注解一般可省略 @JoinColumn(name = "course_id", referencedColumnName = "course_id") @InverseJoinColumn(name = "child_id", referencedColumnName = "student_id") private List<Child> students; }

  

Child實體類配置:

@Data public class Child { @TableId("child_id") private Long id; private String name;

//多對多 @TableField(exist = false) @ManyToMany @JoinTable(targetMapper=StudentCourseMapper.class) @JoinColumn(name = "child_id", referencedColumnName = "student_id") @InverseJoinColumn(name = "course_id", referencedColumnName = "course_id")
private List<Course> courses; }

 

StudenCourse中間類(多對多必須要有,如果命名為StudentCourse或CourseStudent,則上邊的@JoinTable可省略):

@Data public class StudentCourse { //可以有也可以無此ID
    private Long id; @TableField("student_id") private Long studentId; @TableField("course_id") private Long courseId; }

 多對多表結構:course: (course_id,  name)          child: (child_id,   name)       student_course:(id,   student_id,    course_id)

 

 

 

mprelation 關聯查詢,使用過程:   

1.   POM中引入mprelation:

 

<dependency>
     <groupId>com.github.dreamyoung</groupId>
     <artifactId>mprelation</artifactId>
     <version>0.0.3.2-RELEASE</version> 
</dependency>

 

 

 

配置 AutoMapper (只要是掃描被注解的實體類)

@Configuration public class AutoMapperConfig { @Bean public AutoMapper autoMapper() { return new AutoMapper(new String[] { "demo.entity","demo.bean" }); //配置實體類所在目錄(可多個,暫時不支持通過符*號配置) } }

 

2.   在實體類中配置注解(更多的注解配置見上邊注解部分,這里只列出其中一個)

 

@Data
@AutoLazy  //不需要手動觸發加載延遲屬性,當延遲屬性被調用時自動創建Session進行獲取。可見如果有多個延遲屬性需要被使用時,會造成多次創建Session,此時可以標注為AutoLazy(false)或不標注,然后采用initialze方法手動一次性加載需要的屬性
public class Man { 
 @TableId(value = "man_id") private Long id; private String name; private Long laoPoId;
@TableField(exist
= false) @OneToOne @JoinColumn(name = "lao_po_id", referencedColumnName = "woman_id") private Woman laoPo;
@TableField(
"company_id") private Long companyId; @TableField(exist = false) @ManyToOne @JoinColumn(name = "company_id", referencedColumnName = "company_id")
private Company company;
@TableField(exist
= false) @OneToMany @JoinColumn(name = "man_id", referencedColumnName = "lao_han_id")
@Lazy(false)
private List<Child> waWa;
 @TableField(exist = false) @OneToMany @JoinColumn(name = "man_id", referencedColumnName = "man_id") @Lazy(false) private Set<Tel> tels;  }

 

 

 

3.   在Service層、Mapper層的使用,見下面:

 

以下是基於Mybatis-Plus官方示例修改而來的測試程序: 

 

 通過繼承工具類重寫過的IService /  ServiceImpl   會自動執行關聯映射, 無須再寫gettLinkById之類的方法(可以使得各實現類沒有任何方法):

 mapper接口:

public interface ManMapper extends BaseMapper<Man> {}

 service接口:

public interface IManService extends IService<Man> {} // IService為重寫過的同名接口

 Service實現:

@Service public class ManServiceImpl extends ServiceImpl<ManMapper, Man> implements IManService {} // ServiceImpl為重寫過的同名接口

 

測試調用:

public class ServiceTest { @Autowired ManService manService; @Test public void t_man_serviceImpl() { Man man = manService.getById(1); // 原Mybatis-Plus的ServiceImpl的各種查詢,被重寫過后,都可以自動關聯,
System.out.println(man);
} }

 

結果輸出:

Man(
id=1,
name=程序猿小明,
laoPoId=1,
laoPo=Woman(id=1, name=程序猿小明老婆, laoGongId=1, laoGong=null, waWa=null),
companyId=1,
company=Company(id=1, name=百度, employees=null),
waWa=[
Child(id=1,name=xxx1,lao_han_id=null, laoHan=null, lao_ma_id=null, laoMa=null, courses=null),
Child(id=2,name=xxxx2, lao_han_id=null, laoHan=null, lao_ma_id=null, laoMa=null, courses=null)
],
tels=[
Tel(id=1, tel=139xxxxxx, manId=1, laoHan=null),
Tel(id=4, tel=159xxxxxx, manId=1, laoHan=null),
Tel(id=2, tel=137xxxxxx, manId=1, laoHan=null)
]
)

 

如需需要對其關聯屬性對象的關聯屬性進行自動加載,可以繼續使用AutoMapper對象的mapperEntity、mapperEntityList、mapperEntitySet、mapperEntityPage來操作:

比如想獲取(填充)waWas 的關聯,則:

List waWas=man.getWaWas(); autoMapper.mapperEntityList(waWas); 

 

AutoMapper類中的幾個常用方法說明:

        mapperEntity(entity)                                            可以對一個實體類,實現自動關聯。

       mapperEntityList(entity_list)                                可以對一個實體類List,實現自動關聯。

       mapperEntitySet(entity_set)                                可以對一個實體類Set,實現自動關聯。

       mapperEntityCollection(entity_list_or_set)          可以對一個實體類Set或List,實現自動關聯。

       mapperEntityPage(entity_page)                          可以對一個實體類Page,實現自動關聯。

       mapper(entity_entityListOrSet_entityPage)         統一上邊的各種方法,直接對實體類,列表,分頁都可以實現自動關聯。


       initialize(entity/entityList/entitySet/entityPage,    OneOrMoreLazyPropertyName ...)                   

       可以對一個實體類/實體類List/實體類Set/實體類Page,在事務范圍內,手動立即觸發其各個被@Lazy(true)標注的關聯屬性。

      該方法在重寫過的ServiceImpl內也存在(供Controller層調用來加載延遲關聯的屬性)。

 

       

 

AutoMapper在重寫過的ServiceImpl類中已經自動注入可用(名為autoMapper),其它情況也可以手動注入:

public class MPRTest2 { @Autowired AutoMapper autoMapper; @Resource private ManMapper manMapper; @Test public void t_man() { Man man = manMapper.selectById(1L); autoMapper.mapperEntity(man); System.out.println(man); } }

  

 

 

 最新版本POM:

 

<dependency>
     <groupId>com.github.dreamyoung</groupId>
     <artifactId>mprelation</artifactId>
     <version>0.0.3.2-RELEASE</version> 
</dependency>

 

 

github:   https://github.com/dreamyoung/mprelation

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM