GVKun编程网logo

@ManyToMany关系无法保存

9

最近很多小伙伴都在问@ManyToMany关系无法保存这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展@ManyToMany/@OneToManymappingby属性用于双向关联

最近很多小伙伴都在问@ManyToMany关系无法保存这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展@ ManyToMany / @ OneToMany mappingby属性用于双向关联、@OneToMany、@ManyToOne以及@ManyToMany讲解(五)、django – 如何在基于过滤器的ManyToMany关系中删除多个对象?、Django与其他字段的ManyToMany关系等相关知识,下面开始了哦!

本文目录一览:

@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属性用于双向关联

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

尚未在@ManyToManyof的中定义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、@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关系中删除多个对象?

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关系

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关系的相关知识,请在本站搜索。

本文标签: