多对多映射
<h2><center>多对多映射</center></h2>
<p>在 POJO 中配置多对多映射
在 POJO 类中字段中增加注解 @ManyMany:</p>
<pre><code class="language-java">@Table("t_food")
public class Food extends Pojo {
@ManyMany(relation = "t_pet_food", from = "foodid", to = "petid")
// 1.r.59之前需要写target参数
// @ManyMany(target = Pet.class, relation = "t_pet_food", from = "foodid", to = "petid")
private List<Pet> pets;
public List<Pet> getPets() {
return pets;
}
public void setPets(List<Pet> pets) {
this.pets = pets;
}
}
@Table("t_pet")
public class Pet {
@Id
public int id;
@Name
public String name;
@ManyMany(relation="t_pet_food",
from="pid",
to="fid")
public List<Food> foods;
}</code></pre>
<h1>插入操作</h1>
<p>如果你已经实现准备好了这样的对象:</p>
<pre><code class="language-java">Food food = new Food("Fish");
List<Pet> pets = new ArrayList<Pet>();
pets.add(new Pet("XiaoBai"));
pets.add(new Pet("XiaoHei"));
food.setPets(pets);</code></pre>
<p>那么你可以一次将 food 以及它对应的 pets 一起插入到数据表中,并在关联表中插入对应的记录</p>
<p>dao.insertWith(food, "pets");
Nutz.Dao 会根据正则表达式 "pets" 寻找可以被匹配上的映射字段(只要声明了 @One, @Many, @ManyMany 任何一个注解,都是映射字段) 并根据注解具体的配置信息,执行相应的 SQL。比如上面的操作,会实际上:</p>
<pre><code class="language-sql">执行 SQL : INSERT INTO t_food (name) VALUES("Fish");
执行 SQL 获取 最大值: SELECT MAX(id) FROM t_food // 假设返回的值是 6
循环 food.pets
执行 SQL: INSERT INTO t_pet (name) VALUES("XiaoBai");
执行 SQL 获取 最大值: SELECT MAX(id) FROM t_pet // 假设返回的值是 97
执行 SQL 插入关联: INSERT INTO t_pet_food (foodid, petid) VALUES(6, 97);
...</code></pre>
<p>这里通过 SELECT MAX 来获取插入的最大值,是默认的做法,如果你想修改这个默认做法,请参看 关于主键一章。</p>
<p>这里因为是多对多映射,所以会首先插入主对象并循环插入映射对象,以便获得双发的主键
如果你的对象中包括多个 @ManyMany 字段,被你的正则式匹配上,那么这些字段对应的字段(如果不为null)都会被匹配,一次被执行
当然,你要想选择仅仅只插入映射字段的话,你可以:</p>
<pre><code class="language-java">dao.insertLinks(food,"pets");</code></pre>
<p>如果 food.id 的值为 6,那么上述操作实际上会执行:</p>
<pre><code class="language-sql">循环 food.pets
执行 SQL: INSERT INTO t_pet (name) VALUES("XiaoBai");
执行 SQL 获取 最大值: SELECT MAX(id) FROM t_pet // 假设返回的值是 97
执行 SQL 插入关联: INSERT INTO t_pet_food (foodid, petid) VALUES(6, 97);
...</code></pre>
<p>看,并不会插入 food 对象。</p>
<p>如果你已经存在了 food 和 pets 对象,你仅仅打算将它们关联起来,那么你可以</p>
<pre><code class="language-java">dao.insertRelation(food,"pets");</code></pre>
<p>如果 food.id 的值为 6,那么上述操作实际上会执行:</p>
<pre><code class="language-sql">循环 food.pets
执行 SQL 插入关联: INSERT INTO t_pet_food (foodid, petid) VALUES(6, 97);
...</code></pre>
<p>看,仅仅只会插入 food 和 pets 的关联</p>
<h1>获取操作</h1>
<p>仅仅获取映射对象:</p>
<pre><code class="language-java">
Food food = dao.fetch(Food.class, "Fish");
dao.fetchLinks(food, "pets");</code></pre>
<p>或者</p>
<pre><code> List<Food> foodList = dao.queryByJoin(Food.class, "pets",Cnd.NEW().and("name","=","Fish"));</code></pre>
<p>queryByJoin框架会 让@One关联的属性,通过left join一次性取出. 与query+fetchLinks是等价的</p>
<p>这会执行操作:</p>
<p>执行 SQL: SELECT <em> FROM t_food WHERE name='Fish'; // 如果 food.id 是6
执行 SQL: SELECT </em> FROM t_pet WHERE id IN (SELECT petid FROM t_pet_food WHERE foodid=6)
但是 Nutz.Dao 没有提供一次获取 food 对象以及 pets 对象的方法,因为,你完全可以把上面的两句话写在一行上:</p>
<pre><code class="language-java">Food food = dao.fetchLinks(dao.fetch(Food.class, "Fish"), "pets");</code></pre>
<p>然后,你可以通过 food.getPets() 得到 Nutz.Dao 为 food.pets 字段设置的值。</p>
<h1>更新操作</h1>
<p>同时更新 food 和 pet</p>
<pre><code class="language-java">dao.updateWith(food, "pets");</code></pre>
<p>这会执行</p>
<p>执行SQL: UPDATE t_food ....
循环 food.pets 并依次执行SQL: UPDATE t_pet ...
仅仅更新 pets</p>
<pre><code class="language-java">dao.updateLinks(food, "pets");</code></pre>
<p>这会执行</p>
<p>循环 food.pets 并依次执行SQL: UPDATE t_pet ...</p>
<h1>删除操作</h1>
<p>同时删除 food 和 pets</p>
<pre><code class="language-java">dao.deleteWith(food, "pets");</code></pre>
<p>仅仅删除 pets</p>
<pre><code class="language-java">dao.deleteLinks(food, "pets");</code></pre>
<p>清除 pets</p>
<pre><code class="language-java">dao.clearLinks(food, "pets");</code></pre>
<p>删除与清除的区别在于</p>
<ul>
<li>删除不仅会删掉 t_pet_food 里的记录,还会逐个调用 dao.delete 来删除 pet 对象。</li>
<li>而清除只会执行一条 SQL 来删除 t_pet_food 中的记录(即中间表中的记录),但是 t_pet 和 t_food 表中的数据不会被删除。</li>
</ul>
<p>详细文档:<a href="https://nutzam.com/core/dao/links_many_many.html">https://nutzam.com/core/dao/links_many_many.html</a></p>