<commit_before>#title:多对多映射
#index:0,2
-------------------------------------------------------------------------------------------------------------
什么是多对多映射

	有两张数据表，通过第三张数据表来表示关联关系，我们称之为多对多的映射
	
	<links_manymany.png>

	如上图，通过一个中间数据表的两个字段，分别指向两个对象的主键，可以实现多对多映射。所以，Pet.foods（一个 `List<Food>`）
	或者 Food.pets（一个`List<Pet>`）就是多对多映射。
	
-------------------------------------------------------------------------------------------------------------
在 POJO 中配置多对多映射

	在 POJO 类中字段中增加注解 {*@ManyMany}：
	{{{<JAVA>
	@Table("t_food")
	public class Food extends Pojo {

		@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;
		}

	}
	}}}
	
	在 Food 对象中必须存在一个 `List<Pet>` 类型的字段，你的多对多映射就需要配置在这个字段上。通过 {*@ManyMany} 注解告诉 Nutz.Dao
	对象 Food 和 Pet 之间的关系，其中：
	 * target 表示你要映射的对象类型
	 * relation 为中间数据表的表名，它也支持[dynamic_table_name.man 动态表名]
	 * from 是中间数据表的字段名，这个字段将储存主对象的主键（上例的 Food 的主键）
	 * to  是中间数据表的字段名，这个字段将储存映射对象的主键（上例的 Pet 的主键）
	 
	因此：
	 * 数据库中{*必须}存在一个中间表 t_pet_food
		 * 该表有一个字段 foodid 对应到 Food 对象的主键
		 * 该表有一个字段 petid 对应到 Pet 对象的主键
	 * Nutz.Dao 通过 @ManyMany 这四个属性了解到：
		 * 目标的 POJO 类 ： Pet
		 * 关联表（{#999;_或者说：中间表}）：t_pet_food
		 * 关联表的 foodid 字段对应到是本 POJO （{#999;Food}）主键
		 * 关联表的 petid 字段对应到是目标 POJO （{#999;Pet}） 主键

-------------------------------------------------------------------------------------------------------------		 
你不仅可以在集合类型字段上声明一对多映射

	本 POJO 类的 @Many 映射，可以不止声明在 List 对象上，它还可以声明在
	 * 数组
	 * Map
	 * POJO
	
	详情，可以参看 [links_many.man 一对多映射] 的相关描述
	
-------------------------------------------------------------------------------------------------------------
插入操作

	如果你已经实现准备好了这样的对象：
	{{{<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);
	}}}
	
	那么你可以一次将 food 以及它对应的 pets 一起插入到数据表中，并在关联表中插入对应的记录
	{{{<JAVA>
	dao.insertWith(food, "pets");
	}}}
	Nutz.Dao 会根据正则表达式 "pets" 寻找可以被匹配上的映射字段（只要声明了 @One, @Many, @ManyMany 任何一个注解，都是映射字段）
	并根据注解具体的配置信息，执行相应的 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);
		...
	}}}
	这里通过 SELECT MAX 来获取插入的最大值，是默认的做法，如果你想修改这个默认做法，请参看 [primary_key.man 关于主键]一章。
	
	 * 这里因为是多对多映射，所以会首先插入主对象并循环插入映射对象，以便获得双发的主键
	 * 如果你的对象中包括多个 @ManyMany 字段，被你的正则式匹配上，那么这些字段对应的字段（如果不为null）都会被匹配，一次被执行
	
	当然，你要想选择仅仅只插入映射字段的话，你可以：
	{{{<JAVA>
	dao.insertLinks(food,"pets");
	}}}
	如果 food.id 的值为 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);
		...
	}}}
	看，并不会插入 food 对象。
	
-------------------------------------------------------------------------------------------------------------
获取操作

	仅仅获取映射对象：
	{{{
	Food food = dao.fetch(Food.class, "Fish");
	dao.fetchLinks(food, "pets");
	}}}
	这会执行操作：
	{{{
	执行 SQL: SELECT * FROM t_food WHERE name='Fish'; // 如果 food.id 是6
	执行 SQL: SELECT * FROM t_pet WHERE id IN (SELECT petid FROM t_pet_food WHERE foodid=6)
	}}}
	
	但是 Nutz.Dao 没有提供一次获取 food 对象以及 pets 对象的方法，因为，你完全可以把上面的两句话写在一行上：
	{{{<JAVA>
	Food food = dao.fetchLinks(dao.fetch(Food.class, "Fish"), "pets");<commit_msg>fixed issue #59<commit_after>#title:多对多映射
#index:0,2
-------------------------------------------------------------------------------------------------------------
什么是多对多映射

	有两张数据表，通过第三张数据表来表示关联关系，我们称之为多对多的映射
	
	<links_manymany.png>

	如上图，通过一个中间数据表的两个字段，分别指向两个对象的主键，可以实现多对多映射。所以，Pet.foods（一个 `List<Food>`）
	或者 Food.pets（一个`List<Pet>`）就是多对多映射。
	
-------------------------------------------------------------------------------------------------------------
在 POJO 中配置多对多映射

	在 POJO 类中字段中增加注解 {*@ManyMany}：
	{{{<JAVA>
	@Table("t_food")
	public class Food extends Pojo {

		@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;
		}

	}
	}}}
	
	在 Food 对象中必须存在一个 `List<Pet>` 类型的字段，你的多对多映射就需要配置在这个字段上。通过 {*@ManyMany} 注解告诉 Nutz.Dao
	对象 Food 和 Pet 之间的关系，其中：
	 * target 表示你要映射的对象类型
	 * relation 为中间数据表的表名，它也支持[dynamic_table_name.man 动态表名]
	 * from 是中间数据表的字段名，这个字段将储存主对象的主键（上例的 Food 的主键）
	 * to  是中间数据表的字段名，这个字段将储存映射对象的主键（上例的 Pet 的主键）
	 
	因此：
	 * 数据库中{*必须}存在一个中间表 t_pet_food
		 * 该表有一个字段 foodid 对应到 Food 对象的主键
		 * 该表有一个字段 petid 对应到 Pet 对象的主键
	 * Nutz.Dao 通过 @ManyMany 这四个属性了解到：
		 * 目标的 POJO 类 ： Pet
		 * 关联表（{#999;_或者说：中间表}）：t_pet_food
		 * 关联表的 foodid 字段对应到是本 POJO （{#999;Food}）主键
		 * 关联表的 petid 字段对应到是目标 POJO （{#999;Pet}） 主键

-------------------------------------------------------------------------------------------------------------		 
你不仅可以在集合类型字段上声明一对多映射

	本 POJO 类的 @Many 映射，可以不止声明在 List 对象上，它还可以声明在
	 * 数组
	 * Map
	 * POJO
	
	详情，可以参看 [links_many.man 一对多映射] 的相关描述
	
-------------------------------------------------------------------------------------------------------------
插入操作

	如果你已经实现准备好了这样的对象：
	{{{<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);
	}}}
	
	那么你可以一次将 food 以及它对应的 pets 一起插入到数据表中，并在关联表中插入对应的记录
	{{{<JAVA>
	dao.insertWith(food, "pets");
	}}}
	Nutz.Dao 会根据正则表达式 "pets" 寻找可以被匹配上的映射字段（只要声明了 @One, @Many, @ManyMany 任何一个注解，都是映射字段）
	并根据注解具体的配置信息，执行相应的 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);
		...
	}}}
	这里通过 SELECT MAX 来获取插入的最大值，是默认的做法，如果你想修改这个默认做法，请参看 [primary_key.man 关于主键]一章。
	
	 * 这里因为是多对多映射，所以会首先插入主对象并循环插入映射对象，以便获得双发的主键
	 * 如果你的对象中包括多个 @ManyMany 字段，被你的正则式匹配上，那么这些字段对应的字段（如果不为null）都会被匹配，一次被执行
	
	当然，你要想选择仅仅只插入映射字段的话，你可以：
	{{{<JAVA>
	dao.insertLinks(food,"pets");
	}}}
	如果 food.id 的值为 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);
		...
	}}}
	看，并不会插入 food 对象。
	
	如果你已经存在了 food 和 pets 对象，你仅仅打算将它们关联起来，那么你可以
	{{{<JAVA>
	dao.insertRelation(food,"pets");
	}}}
	如果 food.id 的值为 6，那么上述操作实际上会执行：
	{{{
	循环 food.pets
		执行 SQL 插入关联: INSERT INTO t_pet_food (foodid, petid) VALUES(6, 97);
		...
	}}}
    看，仅仅只会插入 food 和 pets 的关联
-------------------------------------------------------------------------------------------------------------
获取操作

	仅仅获取映射对象：
	{{{
	Food food = dao.fetch(Food.class, "Fish");
	dao.fetchLinks(food, "pets");
	}}}
	这会执行操作：
	{{{
	执行 SQL: SELECT * FROM t_food WHERE name='Fish'; // 如果 food.id 是6
	执行 SQL: SELECT * FROM t_pet WHERE id IN (SELECT petid FROM t_pet_food WHERE foodid=6)
	}}}
	
	但是 Nutz.Dao 没有提供一次获取 food 对象以及 pets 对象的方法，因为，你完全可以把上面的两句话写在一行上：
	{{{<JAVA>
	Food food = dao.fetchLinks(dao.fetch(Food.class, "Fish"), "pets");
{'fraction_non_alphanumeric': 0.26713819368879216, 'fraction_numerical': 0.007616974972796518, 'mean_word_length': 2.2179431072210067, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2536023', 'n_tokens_mistral': 4030, 'n_tokens_neox': 4134, 'n_words': 617}