It seems like there's also no way to make an entit...
# komapper
d
It seems like there's also no way to make an entity without an id... the problem comes up in many-to-many linker tables... they only have two foreign keys, but no primary id key.
t
How about one of the following structures for many-to-many linker table?
Copy code
@KomapperEntity
data class EmployeeProject(
    @KomapperId
    @KomapperAutoIncrement
    val id: Int,
    val employeeId: Int,
    val projectId: Int
)
or
Copy code
@KomapperEntity
data class EmployeeProject(
    @KomapperId
    val employeeId: Int,
    @KomapperId
    val projectId: Int
)
d
#2 is a composite primary key?
t
Yes.
d
I didn't know
@KomapperId
can be used twice in the same class... it might be nice to point that out in the docs... I tried #1, but it's just too verbose for my case...
The only thing is that in the production db, there's no composite primary key there, and I'm afraid of what would happen if I use it then.
Will I be forced to create one?
t
If the existing foreign keys in many-to-many tables are always not null, I think nothing will happen.
d
And lifting the requirement of having at least one id on a table would not be possible?
Any reason that this is imposed?
t
Some queries such as
QueryDsl.update(..).single(..)
require entity identifier.
d
So these kinds of tables shouldn't be used in such queries... maybe there could be
EntityMetamodelWithId
for those queries, but the others would be the base interface
EntityMetamodel
without the id, then those functions wouldn't be able to be called.
I tried making them id's like you suggested, and my tests still pass so far even though I removed the primary key in h2 with executeScript... but this seems pretty hacky, in the code it seems to indicate that there's a primary key which doesn't reflect reality... I'm sure there's tons of cases like this out there... I wonder if there's any better solution, if what I proposed above is maybe a bit too much work.
t
I wonder if there’s any better solution, if what I proposed above is maybe a bit too much work.
Yes, I feel it is a bit too much work. I don’t have any good ideas at the moment.
I consider this is a bad idea but... does this meet your needs?
Copy code
// define entity without id
@KomapperEntity(requiresId = false)
data class Person(...)

// get a metadata
val p = Meta.person

// when you try to run a query that needs id, Komapper throws exception
db.runQuery(QueryDsl.update(p).single(Person(...)))
d
Yeah, that's probably the best way to do things given the alternative isn't possible. An opt-in option that's well documented that it throws in such a situation should at least make things look less hacky for such use-cases as many to many link tables. I think not having this ability is worse.
It'll crash anyways if it has an id annotation and the primary key doesn't really exist...
l
The example you give is not a good one. All tables should have a primary key and in fact many-to-many tables are supposed to have a composite primary key. Having a combination repeated in a linker table is almost guaranteed to return incorrect results.
d
Not in every case, some tables are HUGE and such an index might have repercussions on performance, if the inserts are controlled, you don't need those composite primary keys. But you're right, there are probably better use cases for not having primary keys, like tables that save raw stats
t
Here is my new idea:
Copy code
// Define a linker entity that has virtual IDs
@KomapperEntity
data class Belonging(
    @KomapperId(virtual = true) val employeeId: Int,
    @KomapperId(virtual = true) val departmentId: Int
)

// QueryDsl.create does not generate primary keys for virtual IDs. 
db.runQuery {
    // create table if not exists belonging (employee_id integer not null, department_id integer not null)
    QueryDsl.create(Meta.belonging)
}

// In other operations, virtual IDs are treated like normal IDs.
db.runQuery {
    // delete from belonging as t0_ where t0_.employee_id = 1 and t0_.department_id = 1
    QueryDsl.delete(Meta.belonging).single(Belonging(1,1))
}
l
Sounds like a good solution
d
I guess that's also a possibility... it'll avoid crashing in those odd cases that a user might not want an id on a table and still search it with an "id"... in my case, the table is being used with innerJoins or as a stats table that usually needs aggregation and searching various fields (not the id). If you prefer this though, I don't mind. One way or the other, thanks a lot for all the effort 😃!
t
I made a pull request. Please let me know if you have any suggestions. https://github.com/komapper/komapper/pull/814
153 Views