管理 Grails 应用程序中多个请求的关联

发布于 2024-08-19 05:06:31 字数 712 浏览 11 评论 0原文

我目前正在实现一个 grails Web 应用程序,其中有几个复杂的表单,只要实体或顶级域对象不存在,对关联图的修改就应该在“内存中”(即 http 会话)进行管理。已保存。

例如

从上到下:文档->类别->子类别...

要求:对文档/类别/子类别的修改只能在保存文档时保存,在任何其他情况下都不应保存。

我的第一个方法是将关联 ID 存储在 http 会话中,但这最终会在我的 DocumentController.update 操作中产生大量线索代码,该更新操作将会话状态与当前持久状态

// update some abstract association
for (def Iterator it = documentInstance.association.iterator(); it.hasNext();)  {
  if (!session.association.contains(it.next().someEntity.id))  {
    it.remove()
  }
}

for (def roleTypeId in session.association)  {
  // add/update association
  ... 
}

线索代码同步,当涉及到实际修改时,情况会变得更糟例如类别的数据,这意味着在保存顶级实体时必须分离/重新附加/合并修改的类别对象。

我对你对如此跨度如此之长的作品的想法非常感兴趣。

i am currently implementing a grails web-app, with a couple of complex forms where modifications on an association graph should be managed "in-memory" (that is the http session) as long as the entity or top-level domain object is not saved.

e.g.

top-to-bottom: Document -> Categories -> Sub-Categories ...

requirement: modifications to document/categories/sub-categories should only be saved whenever the document is saved and under no other circumstances.

my first approach was to store the association ids in the http session, but this ends up with lot of clue code in my DocumentController.update action that synchronizes session state with the current persistent state

// update some abstract association
for (def Iterator it = documentInstance.association.iterator(); it.hasNext();)  {
  if (!session.association.contains(it.next().someEntity.id))  {
    it.remove()
  }
}

for (def roleTypeId in session.association)  {
  // add/update association
  ... 
}

clue code is getting even worse when it comes to actually modifying data e.g. of a category, meaning that the modified category object has to be detached/reattached/merged when the top-level entity is saved.

I would be very interested in your thoughts on such long-spanned unit of works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

靑春怀旧 2024-08-26 05:06:31

您可以使用每次对话会话模式,也称为“长对话”。尝试 grails webflow 插件,它以这种方式工作,或者如果您认为 webflow 不适合您的需求,请自行实现每个会话会话。

基本前提是在对话开始时,您打开一个新的休眠会话(刷新模式=手动)并将其存储在用户的http会话中。在每个后续 http 请求开始时,您需要确保 sessionFactory.getCurrentSession 返回会话的休眠会话,并记住在每个请求结束时断开此会话以关闭请求之间的 jdbc 连接。当您到达对话结束时,您刷新会话以保留所有更改,或者关闭而不刷新以取消它们。

hibernate 网站 / Java Persistence with Hibernate 一书有一些关于如何做到这一点的非常好的信息,但除了 webflow 之外,grails 中没有开箱即用的支持。我正在编写 SessionPerConversation 插件,但现在还处于早期阶段。我的方法是查看 grails 1.2.0 源代码并复制它们如何实现 .withNewSession,然后用 .withConversation、.endConversation 和 .discardConversation 的方法装饰我的控制器。当我进一步了解时,我可能会在 State Your Bizness 上发布一些

代码到目前为止,我们遇到过...

  1. 如果用户从未结束对话,则休眠会话将保持打开状态(尽管不是 jdbc 连接),直到其 http 会话超时。如果您支持多个对话,那么每个用户可能有多个休眠会话,对于高使用率站点,您可能会遇到内存问题

  2. 您必须注意自动会话刷新。当您新建实体时,可能会发生这种情况,具体取决于您用于 id 生成的策略,或者您是否调用事务服务

You could use the session-per-conversation pattern a.k.a. "long conversations". Try the grails webflow plugin, which works this way or if you think webflow is inappropriate for your needs implement session-per-conversation yourself.

The basic premise is at the start of a conversation you open a new hibernate session (with flush mode = manual) and store it in the users' http session. At the start of each subsequent http request you need to ensure sessionFactory.getCurrentSession returns the conversation's hibernate session, and remember to disconnect this session at the end of each request to close the jdbc connection between requests. When you reach the end of the conversation you flush the session to persist all changes, or close without flushing to cancel them.

The hibernate web site / Java Persistence with Hibernate book has some really good info on how to do this, but other than webflow there's no out of the box support in grails. I'm in the process of writing a SessionPerConversation plugin, but it's very early days. My approach was to look at the grails 1.2.0 source code and copy how they implemented .withNewSession, then decorate my controllers with methods for .withConversation, .endConversation and .discardConversation. When I've got a bit further I'll probably post some code on State Your Bizness

The gotchas I've come across so far are...

  1. If the user never ends their conversation the hibernate session will be kept open (although not the jdbc connection) until their http session times out. If you support multiple conversations, then each user may have multiple hiberate sessions and for a high usage site you could get memory problems

  2. You have to watch out for automatic session flushing. This can happen when you new up entities depending on which strategy you use for id generation, or if your calling transactional services.

才能让你更想念 2024-08-26 05:06:31

一些想法:

将代码从控制器中分离出来并将其放入服务中。

将服务的静态“事务”属性设置为 false 并控制事务。它可能看起来有点像这样:

class DocumentService {
    // take control from spring
    static transactional = false

    void updateMethod() {
        Document.withTransaction { transact ->
            // handle your business

            // problems? - you can always rollback without breaking anything
            transact.setRollbackOnly()
        }
    }
}

这将允许您使用“def documentService”行将服务注入到控制器中。您可以处理服务中的所有逻辑并更彻底地测试所有内容。

Some thoughts:

Break your code out of the controller and put it in a service.

Set the static 'transactional' property of the service to false and take control of the transaction. It might look a little like this:

class DocumentService {
    // take control from spring
    static transactional = false

    void updateMethod() {
        Document.withTransaction { transact ->
            // handle your business

            // problems? - you can always rollback without breaking anything
            transact.setRollbackOnly()
        }
    }
}

This will let you inject the service into your controller with the line 'def documentService'. You can handle all of your logic in the service and test everything more thoroughly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文