Implementing hierarchical DB tables with InheritanceType.JOINED and a `tenant_id` column in every table - spring-boot

I'm trying to implement a hierarchical structure using the InheritanceType.JOINED approach to store data in hierarchical DB tables. One caveat is that in our multi-tenant solution, a tenant_id column needs to be present on every table (for security and legal export reasons), even though this is redundant in some cases. This requirement is fixed.
Issue is that when inserting data, the query Hibernate generates does not fill in the tenant_id on the parent- and childtable, causing a constraint error.
The tables in the DB would look like this:
Code for the abstract vehicle entity:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
abstract class Vehicle(
var tenantId: Int,
var title: String
)
Car entity:
#Entity
class Car(
override var tenantId: Int,
override var title: String,
) : Vehicle(tenantId, title) {
var numberOfDoors: Int
}
Plane entity:
#Entity
class Plane(
override var tenantId: Int,
override var title: String,
) : Vehicle(tenantId, title) {
var numberOfPropellers: Int
}
When inserting a new Car in the database, Hibernate generates 2 queries, where the tenant_id is only added to the abstract Vehicle table:
insert into vehicle (tenant_id, title) values (?, ?)
insert into car (id, number_of_doors) values (?, ?)
Is there a way to instruct Hibernate to fill in the column on both tables?
One hack I've found is to implement a "second" tenantId variable on the class and specify a column explicitly, as such:
#Column(name = "tenant_id")
private val _tenantId: Int = tenantId
But it's not very clean and a neater solution would be nice.

Specifically in my case where the tenant_id column is a database setting, defining a computed default value on the tenant_id db column also works as a workaround:
current_setting('app.current_tenant', true)::INT

Related

User defined fields in graphQL

Making an employee management system with graphene-Django and I have a JsonB field that I don't know the shape of because each company will defined the shape.
Here's the model:
class Employee(models.Model):
bonuses = models.JSONField(default=dict)
#...OTHER FIELDS
here's the type:
class EmployeeType(DjangoObjectType):
class Meta:
model = Employee
fields = "__all__"
Here's the mutation class:
class EmployeeInfo(graphene.Mutation):
employee = graphene.List(EmployeeType)
class Arguments:
bonuses = GenericScalar()
#...OTHER FIELDS
def mutate(self, info, **kwargs):
#DOING STUFF
return EmployeeInfo(employee=employee)
Now, say a company wants to give bonuses to a developer with the following schema:
export const EMPLOYEE_INFO = gql`
mutation MutateEmployee(
$employeeOfTheMonth: Int
$mostPR: Int
$profitSharing: Int
) {
employeeInfo(
bonuses:{
employeeOfTheMonth: $employeeOfTheMonth
mostPR: $mostPR
profitSharing: $profitSharing
}
#...OTHER FIELDS
){....}
}
`
This is my current setup, the problem is I get only null values in the database for the bonuses field. Notice that I'm using GenericScalar which is not documented and I don't know if that's the wrong scalar.
If this is a restaurant, obviously the bonuses will be different and that's why I need a setup like this.
How can I define a field that will take user defined shapes?
I think this is what you need
class EmployeeInfo(graphene.Mutation):
employee = graphene.List(EmployeeType)
class Arguments:
bonuses = graphene.JSONString()
#...OTHER FIELDS

Polymorphism in Prisma Schema - Best practices?

This is more a design question than a coding question. Suppose the following schema:
// schema.prisma
// Solution 1
model Entity {
id Int #id #default(autoincrement())
attrs EntityAttr[]
}
model EntityAttr {
id Int #id #default(autoincrement())
value Json // or String, doesnt matter much here
// the point is I need to attach info on the
// join table of this relation
attr Attr #relation(fields: [attrId], references: [id])
entity Entity #relation(fields: [entityId], references: [id])
entityId Int
attrId Int
##unique([entityId, attrId])
}
model Attr {
id Int #id #default(autoincrement())
entities EntityAttr[]
}
// Solution 2
model Entity {
id Int #id #default(autoincrement())
dateAttrs DateAttr[]
recordAttrs RecordAttr[]
// ... this pattern could continue for more Attr-like models
}
model DateAttr {
id Int #id #default(autoincrement())
name String
entity Entity #relation(fields: [entityId], references: [id])
value DateTime // Stronger typing in generated code
}
model RecordAttr {
// ... define another Entity #relation(...)
name String
value String
// ...
}
// ... and so on
Please note that the schema might not be 100% complete or accurate. It is mainly to get the point across.
Solution 1 has its merits where redundancy and the number of tables in the database is reduced significantly (depending on the number of Attrs). Its downfall comes as confusing queries*, possible case-specific type casting and no code-completion for the value field for each Attr-like model.
* by confusing, I mean that the option for simplified m-n queries in prisma is functionally disabled when using a custom join table (e.g. EntityAttr)
Solution 2 has its merits where the generated code results in more strongly typed code generation for the value field, however it falls in the number of generated tables (I don't actually know if more tables is a good thing or a bad thing, all I think is that if you have similar values, they ought to be in the same table).
What would you do in my shoes?
I was looking pretty long for an appropriate answer and found it here.
I'm not sure if it could be applied to your question, but this is question about prisma and polymorphism, so I think this code snippet might be useful for developers:
model Photo {
id Int #id #default(autoincrement())
likes Like[] #relation("PhotoLike")
}
model Video {
id Int #id #default(autoincrement())
likes Like[] #relation("VideoLike")
}
enum LikableType {
Photo
Video
}
model Like {
id Int #id #default(autoincrement())
Photo Photo? #relation("PhotoLike", fields: [likableId], references: [id], map: "photo_likableId")
Video Video? #relation("VideoLike", fields: [likableId], references: [id], map: "video_likableId")
likableId Int
likableType LikableType
}
Resuling relations in dbdocs:
Sometimes the use case can't be generalized to abstract and have a typing's.
if you control them and has a limited attribute sure you can create each attribute as a separate table each has it is own schema.
Some Times more freedom is needed or the blocks are dynamic.
Use Case: Build A Block Document Editor Like 'notion.so' and you want to let the user create custom blocks or configure them.
you can do it like :
model Document {
id String #id
blocks Block[]
}
model Block {
id String #id
value Json
index Int
customConfig Json?
document Document? #relation(fields: [documentID], references: [id])
documentID String?
blockType BlockType #relation(fields: [blockTypeID], references: [id])
blockTypeID String
}
model BlockType {
id String #id
name String
config Json
blocks Block[]
}
where config and custom config can contains html,custom css classes, link attribute color or anything.
using type script you can create block.types.ts and add different let say templates for the config's .
I hope that I was useful to you, To sum it, it depends on the requirements :>)

How to gracefully transform entity into DTO in Kotlin?

I am working on Kotlin + SpringBoot web service, in which I want to transform DTOs into entities in the most convenient way.
Entities:
#Entity
data class Shop(
#Id
#GeneratedValue
val id: Long,
val name: String
#OneToOne
val owner: User,
...
)
#Entity
data class User(
#Id
#GeneratedValue
val id: Long,
val name: String,
...
)
DTO:
data class ShopDTO(
val id: Long,
val name: String,
val ownerId: Long,
val ownerName: String,
...
)
So when someone wants to create a new Shop, my service gets a ShopDTO(name, ownerId) as request body, then I need to transform it into Shop object to be able to save it to the DB. Now here is how my mapper function looks like:
fun fromDTO(source: ShopDTO) = Shop(
id = source.id,
name = source.name,
owner = ???,
...
)
To be able to store a Shop with an owner I only need an id. It would be enough to create a new User with the given ownerId.
To achive this I tried these solutions:
Add default value to the fields in the User class.
Make the fields nullable.
Add a secondary constructor. This also needs default values.
Use some reflection magic to create an empty object and then set the id.
Call a findById method on the UserRepository with the given id.
I want to keep the non-null, immutable fields of my entities and do not want to use reflection. Also do not want to run an unnecessary select DB query just to get back the user by the id.
Could you please suggest me other options? How would you handle this situation? Is there any good mapper framework in Kotlin which can solve this problem?
Firstly, your question says you want to do entity -> DTO, but actually you want to do DTO -> entity, so you should clear that up.
Secondly, you are getting the shop name and owner Id in the ShopDTO. But you are assigning the owner Id to the shop Id in the your fromDTO(source: ShopDTO) function. Changing it up would be sufficient.
fun fromDTO(source: ShopDTO) = Shop(
name = source.name,
owner = ownerRepo.findById(source.ownerId)
)
Obviously, if you're using JPA, then you have to make a DB call to get the owner first. If your business logic doesn't ensure that a User with that Id exists, then you could write a method like this to make a user.
fun getOrCreateUser(ownerId: Long) =
ownerRepo.findUserById(ownerId) ?: User(
id = ownerId,
name = "Some random DefaultName"
).run(ownerRepo::save)
This would get a User by the Id if it exists, or create a new user with some generic name.
Do let me know if this solves your issue!

Get String from SQL function, no entity, kotlin

Im confused..
I need to use Oracle function to retrieve just a single String, No entity.
So i try to use CrudRepository, but that dosent work without Entity?
interface UserRepository : CrudRepository<Contact, String>{
#Query(nativeQuery = true, value = "SELECT schema.get_user(:id) FROM DUAL")
fun getUser(id: String): String?
}
or
interface UserRepository : CrudRepository<Contact, String>{
#Query(nativeQuery = true, value = "SELECT schema.get_user(:id) AS name, '' AS email FROM DUAL")
fun getUser(id: String): String?
}
where i try to name returning string to fit entity i seem to be forced to use.
Entity Contact is super simple entity with two attributes.
#Entity
data class Contact(
#Id
val name: String?,
val email: String?
)
Function will only ever return one string, but i cant figure how would i insert that as a name.. With this Query i get ORA-00904: : invalid identifier most likely because i have no idea how to match identifier returned from function.. (SQLdeveloper gives function name as column name but the returned string dosent really have ANY column name, since it is calculated...)
I can't do a repository for a String either, can i?
EDIT: trying to clarify what i need:
Entity has two attributes, just one comes from the Query including function, other one must be fetch from other side of the world. How do i run this query and return either single string or entity (with email as null) only have gotten array of errors so far, thanks

Servicestack Ormlite multi-column constraint fails where constraint includes Enum

I am using ServiceStack.Ormlite, and also make heavy use of the automatic handling of enums whereby they are stored in the db as strings but retrieved and parsed nicely back into Enums on retrieval, so I can do easy type-comparison - say, for a property "UserRole" in the db/table class "User" of enum type "UserRoleEnum" (just for demonstration).
This works great.. until I want to use the enum property to define a multi-column unique constraint
CompositeIndexAttribute(bool unique, params string[] fieldNames);
like:
[CompositeIndex(true, nameof(UserId), nameof(UserRole)]
public class User
{
public long UserId {get;set;}
public UserRoleEnum UserRole {get;set;
}
(as per :
How to Create Unique Constraint with Multiple Columns using ServiceStack.OrmLite? ).
At which time i get:
System.Data.SqlClient.SqlException
Column 'UserRole' in table 'User' is of a type that is invalid for use as a key column in an index.
I currently see options as:
a) Define UserRole as a string (isntead of UserRoleEnum ) in the table entity class and lose the Enum use.... having to manually test the value each time to confirm that the db value is one that i expect in my business logic later
b) Continue to use UserRoleEnum but lose the ability to declare multicolumn uniqueconstraints using the class attribute, and probably have to create these manually using a subsequent db migration script?
Is there any way to make the enums and the multicolumn constraint play nicely, out of the box?
This issue was because enum properties were using the default string definition fallback of VARCHAR(MAX) which SQL Server doesn't let you create indexes on whereas the column definition of a string property is VARCHAR(8000).
This issue is now resolved from this commit which now uses the VARCHAR(255) string definition of the EnumConverter Type Converter. This change is available from v4.5.5 that's now available on MyGet.
Otherwise you can also change the size of the column definition to match a string property by adding a [StringLength] attribute, e.g:
[CompositeIndex(true, nameof(UserId), nameof(UserRole))]
public class User
{
public long UserId { get; set; }
[StringLength(8000)]
public string UserRole { get; set; }
}

Resources