最近很多小伙伴都在问@ManyToMany关系无法保存这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展@ManyToMany/@OneToManymappingby属性用于双向关联
最近很多小伙伴都在问@ManyToMany关系无法保存这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展@ ManyToMany / @ OneToMany mappingby属性用于双向关联、@OneToMany、@ManyToOne以及@ManyToMany讲解(五)、django – 如何在基于过滤器的ManyToMany关系中删除多个对象?、Django与其他字段的ManyToMany关系等相关知识,下面开始了哦!
本文目录一览:- @ManyToMany关系无法保存
- @ ManyToMany / @ OneToMany mappingby属性用于双向关联
- @OneToMany、@ManyToOne以及@ManyToMany讲解(五)
- django – 如何在基于过滤器的ManyToMany关系中删除多个对象?
- Django与其他字段的ManyToMany关系
@ManyToMany关系无法保存
我有一些与@ManyToMany
关系有关的实体:
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)@JoinTable(name = "buses_drivers", joinColumns = @JoinColumn (name = "driver_id_inner", referencedColumnName = "driver_id"), inverseJoinColumns = @JoinColumn (name = "bus_id_inner", referencedColumnName = "bus_id"))private List<Bus> buses;
和
@ManyToMany(mappedBy = "buses", fetch = FetchType.EAGER, cascade = CascadeType.ALL)private List<Driver> drivers;
Driver
使用某些Bus
模型执行保存模型时,一切正常。表buses_drivers
存储这些实体的所有键。但是,Bus
使用驱动程序保存模型时,表不会更改。我认为inverseJoinColmns
映射存在问题。
答案1
小编典典那是预期的行为。在双向多对多关联中,一侧必须是反侧。在您的情况下,这是Bus
一面,因为它包含mappedBy
:
拥有关系的字段。除非关系是单向的,否则为必需。
这意味着Driver
是关联的所有者,并且Hibernate仅在维护关联时检查该侧。
@ ManyToMany / @ OneToMany mappingby属性用于双向关联
我正在为我的实习工作开发JPA兼容套件…该套件的一部分涉及测试极端情况的正确实现。
@ManyToMany
具有mapedBy属性。JPA指出:
字符串mappingBy-拥有关系的字段或属性。除非关系是单向的,否则为必需。
没有给出默认值-默认列为空。
给定双向@ManyToMany
-此示例来自JPA 2.0 JSR-317规范本身!
顾客
@ManyToMany@JoinTable(name="CUST_PHONES")public Set<PhoneNumber> getPhones() { return phones; }
电话号码
@ManyToMany(mappedBy="phones")public Set<Customer> getCustomers() { return customers; }
尚未在@ManyToMany
of的中定义mapledBy属性Customer
!我不知道的双向映射有默认值吗?
我查看了类似的情况,发现: @OneToOne
-mappingBy是可选的,没有默认值@OneToMany
-完全相同@ManyToMany
(mappedBy对于双向是可选的,没有默认值)
简而言之,我的问题是:
对于@ManyToMany
和@OneToMany
,应在关系的拥有方(Customer
例如)中将其放置在mappedBy属性中?
答案1
小编典典这绝不是一个极端的情况。每个双向关联都有一个所有者方和一个反向方。
JPA使用拥有方来确定两个实体之间是否存在关联。另一侧被忽略。
拥有方定义了如何映射关联(使用JoinColumn,JoinTable等批注)。它没有任何mappedBy
属性。
反面使用该mappedBy
属性说:“嘿,我只是由以下属性映射的那个的逆关联”。
因此,根据定义,拥有方没有mappedBy
属性。如果有一个,它就不会是拥有者。
JPA规范对此做了很好的解释。如果您需要为此规范构建兼容套件,则最好阅读并理解它。
我真的看不出编写这种兼容工具包的意义,因为正如在JPA2
JSR主页上所写的那样,
- 根据Java规范参与协议(JSPA)的要求,Java Persistence API版本2.0
- TCK将免费获得许可,无需支持合格的非营利实体。此类资格将由兼容性测试奖学金计划进行验证。经奖学金委员会批准,也可以免费提供支持。有关更多信息,请访问:http
- //java.sun.com/scholarship/。
@OneToMany、@ManyToOne以及@ManyToMany讲解(五)
一、一对多(@OneToMany)
1、单向一对多模型
假设通过一个客户实体可以获得多个地址信息。
对于一对多的实体关系而言,表结构有两种设计策略,分别是外键关联和表关联。
(1) 映射策略---外键关联
在数据库中表customer和表结构address定义,如下:
create table customer (
id int(20) not null auto_increment,
name varchar(100),
primary key(id)
)
create table address (
id int(20) not null auto_increment,
province varchar(50),
city varchar(50),
postcode varchar(50),
detail varchar(50),
customer_id int(20),
primary key (id)
)
注意此时外键定义在多的一方,也就是address表中。
此时,表customer映射为实体CustomerEO,代码如下:
@Entity
@Table(name="customer")
public class CustomerEO implements java.io.Serializable {
@OneToMany(cascade={ CascadeType.ALL })
@JoinColumn(name="customer_id")
private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
...
}
注释@OneToMany的定义代码如下:
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default LAZY;
String mappedBy() default "";
}
使用时要注意一下几点问题:
a、targetEntity属性表示默认关联的实体类型。如果集合类中指定了具体类型了,不需要使用targetEntity.否则要指定targetEntity=AddressEO.class。
b、mappedBy属性用于标记当实体之间是双向时使用。
(2) 映射策略---表关联
在上面address表中去掉customer_id字段,在增加一个表ref_customer_address,如下:
--客户地址关系表
create table ref_customer_address (
customer_id int(20) not null,
address_id int(20) not null unique
)
此时表customer映射为CustomerEO实体,代码如下:
@Entity
@Table(name = "customer")
public class CustomerEO implements java.io.Serializable {
...
@OneToMany(cascade = { CascadeType.ALL })
@JoinTable(name="ref_customer_address",
joinColumns={ @JoinColumn(name="customer_id",referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="address_id",referencedColumnName="id")})
private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
...
}
表关联@JoinTable,定义如下:
@Target({METHOD,FIELD})
public @interface JoinTable {
String name() default "";
String catalog() default "";
String schema() default "";
JoinColumn[] joinColumns() default {};
JoinColumn[] inverseJoinColumns() default {};
UniqueConstraint[] uniqueConstraints default {};
}
其中:
a、该标记和@Table相似,用于标注用于关联的表。
b、name属性为连接两张表的表名。默认的表名为:“表名1”+“-”+“表名2”,上面例子默认的表名为customer_address。
c、joinColumns属性表示,在保存关系中的表中,所保存关联的外键字段。
d、inverseJoinColumns属性与joinColumns属性类似,不过它保存的是保存关系的另一个外键字段。
(3) 默认关联
在数据库底层为两张表添加约束,如下:
create table customer_address (
customer_id int(20) not null,
address_id int(20) not null unique
)
alter table customer_address add constraint fk_ref_customer foreign key (customer_id) references customer (id);
alter table customer_address add constraint fk_ref_address foreign key (address_id) references address (id);
这样,在CustomerEO中只需要在标注@OneToMany即可!
二、多对一@ManyToOne
1、单向多对一模型。
(1) 外键关联
配置AddressEO实体如下:
@Entity
@Table(name="address")
public class AddressEO implements java.io.Serializable {
@ManyToOne(cascade = { CascadeType.ALL })
@JoinColumn(name="customer_id")
private CustomerEO customer;
// ...
}
@ManyToOne定义如下:
@Target({METHOD,FIELD}) @Retention(RUNTIME)
public @interface ManyToOne {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fatch() default EAGER;
boolean optional() default true;
}
(2) 默认关联
数据库脚本定义的相关字段的约束,创建外键后,直接使用@ManyToOne
三、高级一对多和多对一映射
即双向关联模型,确定了双向关联后,多的一方AddressEO不变使用@ManyToOne,而CustomerEO实体修改为:
@Entity
@Table(name="customer")
public class CustomerEO {
@OneToMany(mappedBy="customer")
private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
// ...
}
其中,@OneToMany标记中的mappedBy属性的值为AddressEO实体中所引用的CustomerEO实体的属性名。
四、多对多(@ManyToMany)
和一对多类型,不在赘述。@ManyToMany标记的定义如下:
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface ManyToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fecth() default LAZY;
String mappedBy() default "";
}
五、最后,谈谈关于集合类的选择
在映射关系中可以使用的集合类有Collection、Set、List和Map,下面看下如何选择。
1、定义时使用接口,初始化使用具体的类。
如Collection可以初始化为ArrayList或HashSet;
Set可以初始化为HashSet;
List可以初始化为ArrayList;
Map可以初始化为HashMap.
2、集合类的选择
Collection类是Set和List的父类,在未确定使用Set或List时可使用;
Set集合中对象不能重复,并且是无序的;
List集合中的对象可以有重复,并且可以有排序;
Map集合是带有key和value值的集合。
django – 如何在基于过滤器的ManyToMany关系中删除多个对象?
class Item(models.Model): timestamp = models.DateTimeField() class Source(models.Model): items = models.ManyToManyField(Item,related_name="sources")
我可以在给定的时间之前使用以下内容找到所有的Source的项目:
source.items.filter(timestamp__lte=some_datetime)
如何有效地删除与该查询匹配的所有项目?我想我可以尝试这样的事情:
items_to_remove = list(source.items.filter(timestamp__lte=some_datetime)) source.items.remove(*items_to_remove)
但这似乎不好
请注意,我不想删除这些项目,因为它们也可能属于其他来源.我只想删除他们与具体来源的关系.
解决方法
source.items.remove(*source.items.filter(*args))
remove / add方法如下所示
remove(self,*objs) add(self,*objs)
和文档http://www.djangoproject.com/documentation/models/many_to_many/
使用[p1,p2,p3]的形式添加多个示例,所以我会下注相同的删除,看到参数是一样的.
>>> a2.publications.add(p1,p3)
多一点挖掘,remove函数逐个迭代* obj,检查它是否是有效的模型,否则使用值作为PK,然后删除与pk__in的项目,所以我会说是的,最好的方法是首先查询您的m2m表,以删除对象,然后将这些对象传递给m2m管理器.
# django.db.models.related.py def _remove_items(self,source_field_name,target_field_name,*objs): # source_col_name: the PK colname in join_table for the source object # target_col_name: the PK colname in join_table for the target object # *objs - objects to remove # If there aren't any objects,there is nothing to do. if objs: # Check that all the objects are of the right type old_ids = set() for obj in objs: if isinstance(obj,self.model): old_ids.add(obj.pk) else: old_ids.add(obj) if self.reverse or source_field_name == self.source_field_name: # Don't send the signal when we are deleting the # duplicate data row for symmetrical reverse entries. signals.m2m_changed.send(sender=rel.through,action="pre_remove",instance=self.instance,reverse=self.reverse,model=self.model,pk_set=old_ids) # Remove the specified objects from the join table db = router.db_for_write(self.through.__class__,instance=self.instance) self.through._default_manager.using(db).filter(**{ source_field_name: self._pk_val,'%s__in' % target_field_name: old_ids }).delete() if self.reverse or source_field_name == self.source_field_name: # Don't send the signal when we are deleting the # duplicate data row for symmetrical reverse entries. signals.m2m_changed.send(sender=rel.through,action="post_remove",pk_set=old_ids)
Django与其他字段的ManyToMany关系
我想在其中自动创建的ManyToMany联接表中存储一些其他信息。我将如何在Django中做到这一点?
就我而言,我有两个表:“雇员”和“项目”。我要存储的是每个项目中每个员工每小时工作所获得的收入,因为这些价值并不相同。那么,我该怎么做呢?
我想到的是,不是使用方法“ ManyToManyField”,而是显式创建了一个第三类/表来存储这些新信息,并使用“ ForeignKey”方法设置其与“ Employees”和“ Projects”的关系。我很确定它会起作用,但这是最好的方法吗?
答案1
小编典典万一链接中断:
from django.db import modelsclass Person(models.Model): name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2 return self.nameclass Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through=''Membership'') def __str__(self): # __unicode__ on Python 2 return self.nameclass Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
今天关于@ManyToMany关系无法保存的讲解已经结束,谢谢您的阅读,如果想了解更多关于@ ManyToMany / @ OneToMany mappingby属性用于双向关联、@OneToMany、@ManyToOne以及@ManyToMany讲解(五)、django – 如何在基于过滤器的ManyToMany关系中删除多个对象?、Django与其他字段的ManyToMany关系的相关知识,请在本站搜索。
本文标签: