Составной ключ и иерархия

 
 
 
Сообщения:106
Добрый день. Возникла задача для которой никак не могу подобрать устраивающее решение. Для наглядности приведу пример.

Будем организовывать учет штурмовиков в звездолетах. В каждом звездолете летит по 100 тыс. штурмовиков, у каждого на шлеме индивидуальный номер от 1 до 100 000 (нумерация в рамках одного звездолета). Каждый штурмовик имеет непосредственного командира, который тоже имеет командира, .... и так до командующего звездолетом. У каждого штурмовика есть еще какая-то информация, которая для примера не представляет интереса, поэтому мы просто сделаем одно поле info.
Итак:

create table starship(
  id bigint primary key,
  name varchar(100)
)

create table trooper(
  personal_number int not null,
  starship bigint not null refference starship (id),
  info varchar(1000),
  commander int,
  primary key(personal_number, starship),
  foreign key(commander, starship) refference trooper(personal_number, starship)
)


Мы эту информацию хотим всячески CRUD. Для этого делаю классы сущностей. Примерно вот так:

@Entity(name = "starship")
public class Starship (
	@Id
    @Column(name = "id", unique = true)
    private Long id;

    @Column(name = "name")
    private String name;
)

@Entity(name = "trooper")
public class Trooper {

    @EmbeddedId
    private TrooperKey id;

    @Column(name = "info")
    private String info;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns({
            @JoinColumn(name = "commander", referencedColumnName = "personal_number", insertable = false, updatable = false),
            @JoinColumn(name = "starship", referencedColumnName = "starship", insertable = false, updatable = false)
    })
    @NotFound(action = NotFoundAction.IGNORE)
    private Trooper commander;

    @OneToMany(mappedBy = "commander", cascade = CascadeType.ALL, orphanRemoval = true)
    @LazyCollection(LazyCollectionOption.FALSE)
    private Set<Trooper> subitems = new HashSet<>();
	
}

@Embeddable
public class TrooperKey implements Serializable {

    @Column(name = "personal_number")
    private Long personalNumber;

    @ManyToOne()
    @JoinColumn(name = "starship")
    private Starship starship;
	
}


И есть одна загвоздка со связями. Так как у нас две связи с полем "starship", то нам необходимо указать где "insertable = false, updatable = false". Но мы не можем сделать
@JoinColumns({
            @JoinColumn(name = "commander"),
            @JoinColumn(name = "starship", referencedColumnName = "starship", insertable = false, updatable = false)
    })

потому что нужно делать оба поля "insertable = false, updatable = false", или не делать ни одно.

Но тогда при записи у нас поле commander не пишется (((

Подскажите, пожалуйста, как подобные задачи решаются без добавления искусственного первичного ключа id со счетчиком (если конечно они так решаются). И вообще как правильнее реализовать такой функционал?
 
 
Сообщения:48
можно удалить поле
 @EmbeddedId
    private TrooperKey id;

изменить первичный ключ
удалить объект starship и оставить только его id
@Embeddable
public class TrooperKey implements Serializable {
 
    @Column(name = "personal_number")
    private Long personalNumber;
 
   @Column(name = "starship")
    private String starshipId;
	
}

что бы однозначный первичный ключ (для поиска)

@Entity(name = "trooper")
@IdClass(TrooperKey.class)
public class Trooper {

и
@Entity(name = "trooper")
public class Trooper {
@Id
@Column(name = "personal_number")
    private Long personalNumber;
 @Id
    @ManyToOne()
    @JoinColumn(name = "starship")
    private Starship starship;
 


это мы решили проблему с колонкой starshipId
чтоб она зависела от объекта starship
теперь с командером и с командерами

этот блок надо менять c использованием @JoinTable
@ManyToOne(fetch = FetchType.EAGER)
    @JoinColumns({
            @JoinColumn(name = "commander", referencedColumnName = "personal_number", insertable = false, updatable = false),
            @JoinColumn(name = "starship", referencedColumnName = "starship", insertable = false, updatable = false)
    })
    @NotFound(action = NotFoundAction.IGNORE)
    private Trooper commander;


примерно так
    @ManyToOne(fetch = FetchType.EAGER)
    
     @JoinTable(name="trooper_hierachy",joinColumns={
            @JoinColumn(name = "personal_number", referencedColumnName = "personal_number"),
            @JoinColumn(name = "starship", referencedColumnName = "starship")          
    },
    inverseJoinColumns={
            @JoinColumn(name = "commander_id", referencedColumnName = "personal_number"),
            @JoinColumn(name = "commander_starship", referencedColumnName = "starship")          
    }

)
    @NotFound(action = NotFoundAction.IGNORE)
    private Trooper commander;

вроде так
может гдето с синтаксисом накосячил
надо смотреть
Изменен:05 ноя 2018 08:04
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет