JAP: table column with name id but not primary key - jpa

I have a table with the columns vendorid and id (and more, omitted here; using lombok for definition):
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "vendor_store")
public class VendorMeta {
#Id
#Column(name = "vendorid", unique = true)
private String vendorid;
#Column(name = "id", unique = false)
private String id;
}
This is the corresponding repository:
#Repository
public interface VendorMetaRepository extends JpaRepository<VendorMeta, String>, JpaSpecificationExecutor<VendorMeta> {
List<VendorMeta> findByVendorid(String vendorid);
}
I would expect that findByVendorid is returning a single element and findById returns a list, but it's working the opposite way:
Optional vendorMeta = vendorMetaRepository.findById("1");
List vendorMeta2 = vendorMetaRepository.findByVendorid("1");
Both methods return answers for searching vendorid, findbyId is also searching column vendorid.
What do I have to do to get the correct results?

It seems that this is not possible (at least when using lombok). The generated method findById() searches the primary key (whatever the name of this column is) and not the column with the name "id".
It is possible to use any column name for the primary key but not the name "id" for a non-primary-key column.

Related

Fetch Entity Reference by Non-Primary Key Column

I have two entities, "User" and "Record", where the Record references a User but not by the User's primary key, but rather another column that is also unique, namely the username:
#Entity
public class User implements Serializable {
#Id
private Long id;
#NaturalId
private String username;
...
}
#Entity
public class Record {
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "username", referencedColumnName = "username")
private User user;
...
}
When creating a new Record, using Hibernate's getReferenceById does not work:
#Transactional
public Record createRecord(Long userId) {
Record record = new Record()
record.setUser(userRepository.getReferenceById(userId));
return recordRepository.save(record);
}
The not-null constraint on the username column of the Record table is violated since the username is not loaded. This does make sense since the getReferenceById method of the JpaRepository interface just returns a proxy and would not return the username. Using the findById method solves this problem, but executes an additional query that I would like to avoid:
#Transactional
public Record createRecord(Long userId) {
Record record = new Record()
record.setUser(userRepository.findById(userId).orElseThrow(RuntimeException::new);
return recordRepository.save(record);
}
Is it possible to fetch an entity reference via a "natural ID" or another unique column?
Additional things to note:
The database schema is managed by Flyway, even in the test context.
Yes, I could just use the numeric ID as the foreign key reference, but I would like to instead use the username.
I know that I could also forgo using the #ManyToOne relationship all together and just use the username in the record class, but I am more interested in the general possibility of leveraging such unique non-primary key columns with Hibernate/Spring Data JPA to the same extent that IDs can be used.

JPA secodaryTables with composite key

I'm working on a legacy database schema. On this schema there are 2 tables:
clienti 1->many clienti_soc
clienti has the primary key id_cliente, clienti_soc has composite key (id_cliente, id_societa). In my JPA application I need to pick the record of clienti_soc with a specific value of id_societa I'd like to put in my application.properties.
Here how I mapped my entity
#Entity
#Table(name="va_clienti")
#SecondaryTable(name = "va_clienti_soc", pkJoinColumns = #PrimaryKeyJoinColumn(name = "id_cliente"))
#Data
public class Cliente {
#Id
public String idCliente;
public String ragioneSociale;
....
#Column(table = "va_clienti_soc" , name="id_societa")
public String idSocieta = "1"; // <-- ????????
#Column(table = "va_clienti_soc" , name="id_gr_prezzi_partner")
public String idGrPrezziPartner;
}
is there a better way or any best practice to crerate the JPA enity? Is there a cleverer use of #PrimaryKeyJoinColumn annotation?

Mapping from table to entity on non-unique column

I have a table definition which looks like this. I do not have the luxury to change the column defn.
table definition
Table FOO{
F_ID NUMBER, -- PK
CODE VARCHAR2(10), -- NON UNIQUE
F_NAME VARCHAR2(10)
}
Table BAR{
B_ID NUMBER, -- PK
CODE VARCHAR2(10), --NON UNIQUE
B_NAME VARCHAR2(10)
}
I need to map this to two entities.
Please note that the relationship is one to many. that is, one Foo can have multiple Bars from an entity point of view.
However,
the same code, which is the common column is non unique in both tables, and can have multiple values in both tables.
I know this can be solved using a join afterwards, but the Bar information is required for every Foo object that gets loaded up.
Is there a way to map this naturally using ORM using a join on the common column code?
#Entity
#Table(name = "FOO")
class Foo{
#Id
#Column(name = "F_ID", nullable = false)
private Long id;
#Column(name = "F_NAME")
private String fName;
#Column(name = "CODE", nullable = false)
private String code;
//What should be the join condition?
private List<Bar> bars;
}
#Entity
#Table(name = "BAR")
class Foo{
#Id
#Column(name = "B_ID", nullable = false)
private Long id;
#Column(name = "B_NAME")
private String bName;
//Is this required?
//private String code;
}

Use different field for column in subclass of EJB entity

I need some help with the design of my entities.
I have a single table MyEntity with the following columns:
id | column1 | column2 | type
And the entity looks like:
#Entity
#DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "type", length = 255)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class MyEntity {
#id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
}
I would like to be able to have several entities inheriting from MyEntity and where each entity define how they use the columns column1 and column2. I would like to just use one single table for all my subclasses, and use the discriminator.
Like this (the following doesn't work):
#Entity
#DiscriminatorValue("TestClass1")
public class TestClass1 extends MyEntity {
#Column(name = "column1");
private long testField1;
#Column(name = "column2");
private long testField2;
}
#Entity
#DiscriminatorValue("TestClass2")
public class TestClass2 extends MyEntity {
#Column(name = "column1");
private long anotherName1;
#Column(name = "column2");
private long anotherName2;
}
I know this approach is not working, so I am reaching out to you guys for help.
EDIT
I have added the inheritance strategy to the MyEntity class, but SINGLE_TABLE is default, so it shouldn't make a difference.
I have tried two approaches:
1) If I don't put two fields MyEntity named column1 and column2, then I cannot create any named queries in MyEntity such as:
#NamedQuery(name=TEST, query="select m from MyEntity m where m.column1 = :val")
I get the following exception:
Caused by: org.hibernate.QueryException: could not resolve property: column1 of: com.test.MyEntity
I would really prefer to specify the queries in MyEntity and not in the subclasses.
2) If I put the fields (column1 and column2) in MyEntity, then I get the following exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.test.TestClass1 column: column1 (should be mapped with insert="false" update="false")
and I don't know how to move on from here. I'm not sure how to do the mapping, which is suggested in the exception message.

ebean unidirectional #OneToOne relation with unique constraint

I have a User class:
#Entity
public class User extends Model {
#Id
public Long id;
public String email;
public String name;
public String password;
}
and a driver class
#Entity
public class Driver extends Model {
#Id
public Long id;
#OneToOne (cascade = CascadeType.ALL)
#Column(unique = true)
public User user;
}
I want to make sure that the user_id is unique inside the Drivers table. But the code above does not enforce that. (I can create multiple drivers with the same user id).
Ideally, I do not want to add the #OneToOne relations in the User class because there are several different roles inside my app (e.g. driver, teacher, agent etc.) and I don't want to pollute user class with all those relations.
How can I achieve this?
I have tried this code on the model for me, and it worked. One thing to be noted, that you must use #OneToOne annotation to let the ORM knows that you have foreign key reference to other model.
The model look like following:
#Entity
// add unique constraint to user_id column
#Table(name = "driver",
uniqueConstraints = #UniqueConstraint(columnNames = "user_id")
)
public class Driver extends Model {
#Id
public Long id;
#OneToOne
#JoinColumn(name = "user_id")
public User user;
}
It will generate evolution script like this :
create table driver (
id bigint not null,
user_id bigint,
constraint uq_driver_1 unique (user_id), # unique database constraint
constraint pk_driver primary key (id)
);
So, with this method you can make sure that you will have unique user reference on driver table.
Additional Info
Because there is an additional constraint, that is not handled by framework but by the database applied on the model (such as the unique constraint), to validate the input or handling the occurred exception, you can surround Model.save() or form.get().save() expression (saving-the-model) with try-catch block to handle the PersistenceException.