最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Using Spring Boot JPA to model an entity containing a Map of String's to custom objects - Stack Overflow

programmeradmin2浏览0评论

My application uses Spring Boot 3.3.7 with JPA support enabled, which means Hibernate 6 is being used.

I need to define the following Java structure to be persisted using Java entity classes:

  • A Company (e.g. 001),

  • can have many users (e.g. [email protected]),

  • and each User can have many applications (e.g. demo),

  • each Application will have 1 associated Emitter to it, which will basically contain an ID (e.g. 1234-5678).

Here is a tree of the hierarchy:

.
├── 001
│   ├── [email protected]
│   │   └── test
│   │       └── EmitterId (1234-5678)
│   └── [email protected]
│       ├── test
│       │   └── EmitterId (9876-5432)
│       └── demo
│           └── EmitterId (9876-9876)
└── 002
    └── [email protected]
        └── demo
            └── EmitterId (1234-5678)

My goal is to be able to query the database to fetch the Emitter ID by providing 3 pieces of data:

  1. company (001) +
  2. user ([email protected]) +
  3. application (test)

= 1234-5678

If I know these values upfront, I should be able to fetch the associated EmitterId value.

I'm not too familiar with modelling a Map using JPA and below is my first attempt, but I feel like this is not the right way to go about the problem.

Can anyone provide some insight as to how this could be modeled better?

I'm using Liquibase integration with Hibernate to generate changelog's based on the Entity classes.

I'd like the primary key for Company to be the keys from the Map also.

import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.util.Map;

@Entity
public class Company {

  @Id
  private String id;

  @ElementCollection
  private Map<String, User> users;

  // getters / setters
}

User.java:

import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import java.util.Map;

@Entity
public class User {

  @Id
  private String id;

  @ElementCollection
  private Map<String, Application> applications;

  @ManyToOne
  private Company company;

  // getters / setters
}

Application.java:

@Entity
public class Application {

  @Id
  private String id;

  @ManyToOne
  private User user;

  private Emitter emitter;

  // getters / setters
}

Emitter.java:

@Entity
public class Emitter {

  @Id
  private String id;

  // getters / setters
}

My application uses Spring Boot 3.3.7 with JPA support enabled, which means Hibernate 6 is being used.

I need to define the following Java structure to be persisted using Java entity classes:

  • A Company (e.g. 001),

  • can have many users (e.g. [email protected]),

  • and each User can have many applications (e.g. demo),

  • each Application will have 1 associated Emitter to it, which will basically contain an ID (e.g. 1234-5678).

Here is a tree of the hierarchy:

.
├── 001
│   ├── [email protected]
│   │   └── test
│   │       └── EmitterId (1234-5678)
│   └── [email protected]
│       ├── test
│       │   └── EmitterId (9876-5432)
│       └── demo
│           └── EmitterId (9876-9876)
└── 002
    └── [email protected]
        └── demo
            └── EmitterId (1234-5678)

My goal is to be able to query the database to fetch the Emitter ID by providing 3 pieces of data:

  1. company (001) +
  2. user ([email protected]) +
  3. application (test)

= 1234-5678

If I know these values upfront, I should be able to fetch the associated EmitterId value.

I'm not too familiar with modelling a Map using JPA and below is my first attempt, but I feel like this is not the right way to go about the problem.

Can anyone provide some insight as to how this could be modeled better?

I'm using Liquibase integration with Hibernate to generate changelog's based on the Entity classes.

I'd like the primary key for Company to be the keys from the Map also.

import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.util.Map;

@Entity
public class Company {

  @Id
  private String id;

  @ElementCollection
  private Map<String, User> users;

  // getters / setters
}

User.java:

import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import java.util.Map;

@Entity
public class User {

  @Id
  private String id;

  @ElementCollection
  private Map<String, Application> applications;

  @ManyToOne
  private Company company;

  // getters / setters
}

Application.java:

@Entity
public class Application {

  @Id
  private String id;

  @ManyToOne
  private User user;

  private Emitter emitter;

  // getters / setters
}

Emitter.java:

@Entity
public class Emitter {

  @Id
  private String id;

  // getters / setters
}
Share Improve this question edited Jan 29 at 9:19 Mark Rotteveel 109k229 gold badges156 silver badges220 bronze badges asked Jan 28 at 23:15 bobbyrne01bobbyrne01 6,76322 gold badges84 silver badges168 bronze badges 7
  • Why do application test and demo have the same EmitterId ((1234-5678))? – life888888 Commented Jan 29 at 1:30
  • @life888888 They are referencing an SseEmitter ID owned by a specific replica pod in a Kubernetes deployment. The idea is that each replica (pod) should lookup the DB to determine the Emitter ID associated with a specific company+user+application .. once they know the Emitter ID, they can check their in-memory data structure to see if they have the right Emitter instance – bobbyrne01 Commented Jan 29 at 8:25
  • Can a user belong to multiple companies? [email protected] seems under both 001 and 002, which causes problems to the designs and normalization. Same with the application 'demo' vs 'test'. Otherwise, check out JPA tutorials explaining bidirectional 1:M and M:1 relationships (which can use sets, lists or maps). – Chris Commented Jan 29 at 18:11
  • @Chris Yes a User can belong to 1 or more Company. Same applies for Application, it can be associated with 1 or more User – bobbyrne01 Commented Jan 29 at 23:18
  • Then a User has more than one company - it is a Many to Many, not a ManyToOne. You might need to rethink this - Application and Emitter seem the only things not shared around as they are specific to a Company/User context. Application needs a M:1 to User and a M:1 to Company. Company can have Many Applications, as can Users. It isn't clear if every user in a company requires an application, or if the relation is independent - assuming it is a requires, you can use a list of application within Company or use a map with the user as the key. – Chris Commented Jan 30 at 14:18
 |  Show 2 more comments

1 Answer 1

Reset to default 0

It isn't clear how you want to represent this in the database. Some of your comments suggest that Users have many companies (not a ManyToOne), so I suspect you want a single 'application' to have many users and companies as well:

COMPANY

ID Name
1 001
2 002

USER

ID Name
1 [email protected]
2 [email protected]

APPLICATION

ID Name
1 test
2 demo

EMITTER

ID
1234-5678
9876-5432
9876-9876

To join them all up, you need a separate table:

EMITTER_RELATIONS

EMITTER_ID USER_ID COMPANY_ID APP_ID
1234-5678 2 1 1
9876-5432 1 1 1
9876-9876 1 1 2
1234-5678 1 2 2

You can use generated IDs like I have above, or the user, company, application name fields as the ID instead to make it easier if you want. I prefer generated IDs overall, though querying using the names will require joins - so its up to you.

Using the names as IDs though, I'd model this as:

@Entity
public class User {
  @Id
  private String id;

  @OneToMany(mappedBy="user")
  private List<EmmitterRelation> emitterRelations;
}
@Entity
public class Application {
  @Id
  private String id;

  @OneToMany(mappedBy="app")
  private List<EmmitterRelation> emitterRelations;

}
@Entity
public class Company {
  @Id
  private String id;

  @OneToMany(mappedBy="company")
  private List<EmmitterRelation> emitterRelations;

}

@Entity
public class Emitter {
  @Id
  private String id;

  @OneToMany(mappedBy="emitter")
  private List<EmmitterRelation> emitterRelations;
}

public class EmitterRelationID {
  public String company;
  private String user;
  private String app;
}

@Entity
@Table(name = "EMITTER_RELATION")
@IdClass(EmitterRelationID.class)
public class EmitterRelation {
  @Id
  @ManyToOne
  private Company company;
  @Id
  @ManyToOne
  private User user;
  @Id
  @ManyToOne
  private Application app;

  @ManyToOne
  private Emitter emitter;
}
发布评论

评论列表(0)

  1. 暂无评论