首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Spring :向具有ManyToMany关系的实体发送请求

Spring :向具有ManyToMany关系的实体发送请求
EN

Stack Overflow用户
提问于 2021-12-01 21:38:12
回答 1查看 46关注 0票数 1

我正在开发一个数据库,用于添加乐队、音乐家、乐器等。

我有一张桌子“乐队”和一张桌子“音乐家”。他们有一个ManyToMany关系(一个乐队可以有多个音乐家,一个音乐家可以在多个乐队中),有一个额外的桌子BandMusician,有一个embeddedId BandMusicianId。我这样做是因为我希望乐队和音乐家之间的关系也有其他信息,比如音乐家加入乐队的那一年。

代码语言:javascript
代码运行次数:0
运行
复制
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Band {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String genre;
    private int year;

    @OneToOne(mappedBy = "band")
    private Website website;

    @OneToMany(mappedBy = "band")
    private List<Album> albuns;

    @OneToMany(mappedBy = "band")
    private List<BandMusician> musicians;

}


@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonDeserialize(using = MusicianJsonDeserializer.class)
public class Musician {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @JsonFormat(pattern = "dd-MM-yyyy")
    @JsonProperty("DoB")
    @Column(name = "date_of_birth")
    private LocalDate DoB;

    @ManyToMany
    @JoinTable(
            name = "musician_instruments",
            joinColumns = @JoinColumn(name = "musician_id"),
            inverseJoinColumns = @JoinColumn(name = "instrument_id")
    )   
    private List<Instrument> instruments = new ArrayList<>();

    @OneToMany(mappedBy = "musician")
    private List<BandMusician> bands;

    public void addInstrument(Instrument instrument) {
        this.instruments.add(instrument);
    }

}


@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BandMusiciansId implements Serializable{
    
    private static final long serialVersionUID = 1L;

    @Column(name = "band_id")
    private Long bandId;

    @Column(name = "musician_id")
    private Long musicianId;
}


@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BandMusician {

    @EmbeddedId
    private BandMusiciansId id = new BandMusiciansId();

    @ManyToOne
    @MapsId("bandId")
    @JoinColumn(name = "band_id")
    private Band band;

    @ManyToOne
    @MapsId("musicianId")
    @JoinColumn(name = "musician_id")
    private Musician musician;

    private String role;
    private int joined;
}

当我收到"/musician“的帖子请求时,我可以拯救一位音乐家。我使用Jackson来反序列化这样的请求:

代码语言:javascript
代码运行次数:0
运行
复制
{
    "name": "John the Ripper",
    "DoB": "03-12-1965",
    "instruments": "voice, guitar",
    "bands": "Band1, Band2"
}

与杰克逊,我可以得到每个乐队,搜索与BandRepository和创建一个BandMusician。

THE PROBLEM:当我收到请求时,为了创建一个BandMusician,我必须创建一个BandMusiciansId,为此我需要bandId和MusicianId。但我现在正在创作音乐家,所以我没有musicianId。它是在我拯救音乐家的时候自动创建的。

MusicianJsonDeserializer类

代码语言:javascript
代码运行次数:0
运行
复制
public class MusicianJsonDeserializer extends JsonDeserializer<Musician>{

private final InstrumentRepository instrumentRepository;
private final BandRepository bandRepository;

@Autowired
public MusicianJsonDeserializer(
        InstrumentRepository instrumentRepository,
        BandRepository bandRepository
) {
    this.instrumentRepository = instrumentRepository;
    this.bandRepository = bandRepository;
}

@Override
public Musician deserialize(JsonParser p, DeserializationContext ctxt) 
        throws IOException, JacksonException {
    
    ObjectCodec codec = p.getCodec();
    JsonNode root = codec.readTree(p);
    
    Musician musician = new Musician();
    musician.setName(root.get("name").asText());
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    musician.setDoB(LocalDate.parse(root.get("DoB").asText(), formatter));
    
    if (root.get("instruments") != null) {
        String instrumentList = root.get("instruments").asText();
        String[] instrumentArray = instrumentList.split(", ");
        List<Instrument> musicianInstrumentList = new ArrayList<>();
        
        for (String instrument : instrumentArray) {
            Instrument instrumentFound = 
                    instrumentRepository.findByName(instrument)
                    .orElseThrow(RuntimeException::new);
            // TODO custom exception
            musicianInstrumentList.add(instrumentFound);
        }
        
        musician.setInstruments(musicianInstrumentList);
    }
    
    if (root.get("bands") != null) {
        // TODO Stuck here!

我想做的是:在我的MusicianService中,在拯救音乐家之后,我可以创建BandMusician和关系。不过,我认为在服务层中这样做是一个错误的选择。

编辑:为了更容易理解,我创建了一个只有其中相关部分的项目,并将其推送到github (https://github.com/ricardorosa-dev/gettinghelp)。同样,我想要的是能够向"/musician“发送一个帖子,这将被MusicianJsonDeserializer捕获,并为请求体中发送的每个乐队创建一个BandMusicianId和BandMusician。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-04 15:10:03

我有实体、乐队和音乐家,他们之间有一个ManyToMany关系,有一个关联表BandMusician。

我想要的是在同一个请求中创建实体音乐家和关系(BandMusician)。

就我所能收集到的信息而言,这是不可能的,因为为了在关联表(BandMusician)中创建记录,我必须已经创建了音乐家(我正在此请求中创建)。

我试过每一件事,只是想看看是否有可能,但没能做到。但是,即使这是可能的,这也是一个非常糟糕的实践,因为它会使类过于紧密耦合。

明确的解决方案是只创建带有此请求的音乐家,然后发送另一个请求来创建Band和音乐家之间的连接。

我还尝试用一个请求在BandMusician表中创建许多条目,这也是不可能的,因为JsonDeserializer表似乎不接受List<>作为返回类型。我试图避免提出很多要求来创建关系条目(例如,对于一个在五个乐队中的音乐家来说),但似乎最好保持清晰和简单。

我现在为每个请求保存一个音乐家乐队的关系:

代码语言:javascript
代码运行次数:0
运行
复制
{
    "musician": "Awesome musician",
    "band": "Awesome band",
    "role": "guitar",
    "joined": 2003
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70191536

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档