grails / gorm-hibernate5

GORM for Hibernate 5
Apache License 2.0
62 stars 67 forks source link

Can I dynamically register a domain? #875

Open ifree-zm opened 1 month ago

ifree-zm commented 1 month ago

with gorm-hibernate5-spring-boot:7.3.1 my code was:

def groovyCode = """
      package com.example.gorm.entity

      import grails.gorm.annotation.Entity
      import org.grails.datastore.gorm.GormEntity

      @Entity
      class Person implements{
          String firstName
          String lastName
      }

      """
      def groovyClass2= loader.parseClass(groovyCode);
      def person = groovyClass.getDeclaredConstructor().newInstance()
      person.invokeMethod("find", { lastName == "John" })

Running the above code will throw an exception:

Either class [com.example.newgorm.entity.Person] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.

I found that domain will be registered to STATIC_APIS at project startup. Can I dynamically register Person domain now?

matrei commented 1 month ago

Hi, out of curiosity, what is your use case for this? I guess you could try to use the GormEnhancer.registerEntity(PersistentEntity entity) (if you can get a hold of it) or something like that.

ifree-zm commented 1 month ago

Hi, out of curiosity, what is your use case for this? I guess you could try to use the GormEnhancer.registerEntity(PersistentEntity entity) (if you can get a hold of it) or something like that.

@matrei Thank you for your reply! My application scenario is for users to dynamically define domain models and be able to query data, so I need to dynamically compile and generate domains. I have noticed that GormEnhancer. registerEntity (PersistentEntity entity) should meet my requirements, but how should I obtain an instance of GormEnhancer? I have obtained a PersistentEntity through the following code. Is the usage correct?

ApplicationContext applicationContext = grailsApplication.mainContext
MappingContext mappingContext=applicationContext. getBean ('grailsDomainClassMappingContext ') as MappingContext
Class<?> clazz = groovyClass2
PersistentEntity entity=mappingContext. addPersistentEntity (clazz)
ifree-zm commented 1 month ago

Hi, out of curiosity, what is your use case for this? I guess you could try to use the GormEnhancer.registerEntity(PersistentEntity entity) (if you can get a hold of it) or something like that.

@matrei Thank you for your reply! My application scenario is for users to dynamically define domain models and be able to query data, so I need to dynamically compile and generate domains. I have noticed that GormEnhancer. registerEntity (PersistentEntity entity) should meet my requirements, but how should I obtain an instance of GormEnhancer? I have obtained a PersistentEntity through the following code. Is the usage correct?

ApplicationContext applicationContext = grailsApplication.mainContext
MappingContext mappingContext=applicationContext. getBean ('grailsDomainClassMappingContext ') as MappingContext
Class<?> clazz = groovyClass2
PersistentEntity entity=mappingContext. addPersistentEntity (clazz)

@matrei I have made some progress. Through the following code, I have implemented the registration of Person, which triggers a listener and calls the registration logic

@Autowired
    MappingContext mappingContext

def entity = mappingContext.addPersistentEntity(groovyClass2)

But when I try to use it through the following code, I still get an error message "Unknown entity: Person"

def method = entity.newInstance().metaClass.getMetaMethod('find', { lastName == "Tom" })
method.invoke(this, { lastName == "Tom" }).find()
rainboyan commented 1 month ago

I think the main cause of the problem is the GroovyClassLoader, which does not compile the script as we would expect, resulting in code that is not a valid GormEntity. You can check the class file generated by the program to be sure, but it's difficult.

Grails has its own GrailsAwareClassLoader, but it doesn't offer enough flexibility, but you can try it.

ifree-zm commented 1 month ago

I think the main cause of the problem is the GroovyClassLoader, which does not compile the script as we would expect, resulting in code that is not a valid GormEntity. You can check the class file generated by the program to be sure, but it's difficult.

Grails has its own GrailsAwareClassLoader, but it doesn't offer enough flexibility, but you can try it.

Thank you for your answer! I tried the method you mentioned, but the error is still the same as before.

rainboyan commented 1 month ago

@ifree-zm Could you provide a minimal and runnable example to reproduce the error, so I can test it with my version to find out how to fix it.

ifree-zm commented 1 month ago

@ifree-zm Could you provide a minimal and runnable example to reproduce the error, so I can test it with my version to find out how to fix it.

That's great! The attachment is a demo built using Gradle. If you need a demo inherited from Springboot, I can also provide it! Thanks! @rainboyan g-app.zip

ifree-zm commented 1 month ago

@puneetbehl Are there any plans to add this feature?

rainboyan commented 1 month ago

@ifree-zm I spent some time researching and found out that the GORM and Hibernate plugin don't support dynamic registration of entities at this time. Can you elaborate on the background to this feature requirement and how it will work in your application? I think there could be a better way. Dynamically registering entities can extend the functionality of an application, but it can also lead to system security and data security issues.

ifree-zm commented 1 month ago

@ifree-zm I spent some time researching and found out that the GORM and Hibernate plugin don't support dynamic registration of entities at this time. Can you elaborate on the background to this feature requirement and how it will work in your application? I think there could be a better way. Dynamically registering entities can extend the functionality of an application, but it can also lead to system security and data security issues.

@rainboyan I plan to let users design their own domain models and directly manipulate the data. For example, if a user defines a Person model, I can automatically concatenate the code and compile it (if possible), and then obtain a Person through the code [Person. find { name=='Tom'}]. Therefore, I need to dynamically compile the Person class instead of defining it in the code beforehand. I have tried to find other similar frameworks, but none of them are ideal...

rainboyan commented 1 month ago

@ifree-zm Although GORM's Entity seems simple to use, I don't think it's really suitable for users to write and run as a script on the web front end, since anytime there's user input, there's the possibility of error and the need for back-end data validation. It seems that using SQL or HSQL may be able to realize some data query and export functions, sorry, I don't know the specific needs of your system, and can't give a more definite suggestion.

On the other hand, I also don't think Hibernate supports the ability to dynamically configure entities, because if the configuration is changed, it can affect the entire data persistent layer of the framework, causing the system to crash.

ifree-zm commented 1 month ago

@rainboyan Thank you for your suggestion! Of course, this is just an attempt I want to make. Currently, it seems that this idea is not feasible. Perhaps I can find other better ways. Thank you again!