Fórum

Model listeners: in onAfterCreate, the model is not yet persisted?

thumbnail
Peter Mesotten, modificado 14 Anos atrás.

Model listeners: in onAfterCreate, the model is not yet persisted?

Junior Member Postagens: 45 Data de Entrada: 04/02/09 Postagens Recentes
Hi,

I recently created a simple Model Listener that listens to the creation of Blogentries. The purpose of my hook is to automatically add a tag to each Blog Entry that gets created. Therefore I created a Model Listener and implemented the onAfterCreate.

I would suspect that, when inside this method, the BlogEntry is already created and persisted to the database. But this doesn't seem to be the case, as I get exceptions calling BlogsEntryLocalServiceUtil.getBlogsEntry(long). This is no db caching problem, because if I check my DB records they are empty. Even worse, if I create some other objects (f.e. I need to create TagsEntry objects) inside the onAfterCreate(), these are only persisted after the execution of the hook plugin.

This doesn't seem desired behavior. Or should I do things differently??

The way I solve this now is to start a new Thread inside my onAfterCreate which waits 5 secs before doing anything. But that doesn't seem good practice...

Thanks in advance.
thumbnail
Minhchau Dang, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Liferay Master Postagens: 598 Data de Entrada: 22/10/07 Postagens Recentes
The database transaction hasn't been committed, and the model listeners are called before the objects are added to EhCache, so this is expected behavior.

Is there some reason you can't use the BlogsEntry object that's passed to your ModelListener?
thumbnail
Peter Mesotten, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Junior Member Postagens: 45 Data de Entrada: 04/02/09 Postagens Recentes
Minhchau,

Thank you for your quick response!

Actually, what I tried to do is to automatically add a tag to each BlogEntry posted. Therefore I had to listen to the creation of TagsAsset so I could persist a new TagsEntry and add it to the asset. But when I want to update the TagsAsset, my TagsEntry is not yet persisted so it throws a NoSuchTagsEntryException... My TagsEntry should be created using content inside my blog.

Do you see any workaround for this?
Thanks in advance!
thumbnail
Minhchau Dang, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Liferay Master Postagens: 598 Data de Entrada: 22/10/07 Postagens Recentes
Truthfully, this is the sort of customization that makes more sense in the EXT environment than a hook, since what you actually want to change is the EditEntryAction.

Updating Liferay tables that are also touched in the same database transaction is fairly unpredictable (for example, even if you got this working, Liferay later calls setTagsEntries after it adds the TagsAsset, which wipes your new tags entries). Model listeners are more for updating your own portlet tables and calling external services that would like to know about data changes.

However, if you want to use hook and the only two fields you are concerned about are the blog entry id and the blog content, then it'd be cleanest to send a message over the message bus in your onAfterCreate.

It's nearly identical to the idea of spawning off a separate thread (since your thread will live outside of the database transaction, just like a message listener will), but you'd be leveraging existing threads rather than constantly creating your own. You'd still need a delay, so you'd probably be fine just sticking to your idea of using a separate thread.
thumbnail
Peter Mesotten, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Junior Member Postagens: 45 Data de Entrada: 04/02/09 Postagens Recentes
Thank you Minhchau.

I however don't agree that this sort of customization should be done in the EXT environment. If you would change EditXXXAction, you would never really need hooks anyway, right?

The message bus seems an interesting topic. Thanks for the reference.
stratos tzoannos, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Postagens: 6 Data de Entrada: 03/02/10 Postagens Recentes
Hi All,

This is a very interesting topic, indeed. I have the same problem when using onAfterCreate() during user creation. As it seems, I cannot access "contact", user's custom attributes, and moreover, I cannot create an organization and associate the user to it.

In any case, I believe that this is a design problem of Liferay, otherwise there is no point of having a Hook functionality. Actually, "onAfterCreate" method, is really misleading and doesn't serve the needs at all.

Best Regards,
Stratos
thumbnail
Mike Robins, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Postagens: 24 Data de Entrada: 26/07/07 Postagens Recentes
Did you (or anyone else) find a way to add users to an organisation using the onAfterCreate method? I've just spent the day trying to get it to work only to discover, as you have, the model is yet to be persisted and so only certain actions can be carried out.

I also agree the description of onAfterCreate is slightly misleading as I had assumed the creation process had completed by the time it executed.

Thanks,

Mike.
stratos tzoannos, modificado 14 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Postagens: 6 Data de Entrada: 03/02/10 Postagens Recentes
Hi Mike,

No, still I haven't found anything. I just moved the functionality to the "login" process. This could be a workaround for you as well. In this way, all the necessary associations take place only at the time when the user logs in.

Kind Regards,
Stratos
Udaya Ramakrishnan, modificado 12 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Mensagem: 1 Data de Entrada: 25/07/11 Postagens Recentes
hi Mike,

did u find any solution for this. my req is i have to add all org while creating userrs. i used onAfterCreate() but it never works for me. Can u tell me the solution.
hope by this time u would have found the solution.

thanks in Advance
thumbnail
Joseph Toman, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Junior Member Postagens: 25 Data de Entrada: 28/01/11 Postagens Recentes
I'm facing the same problem and I'm glad I found this answer so quickly. I was trying to create an asset link on adding a document to the document library, only to discover there's no asset to link to!

Here's my rant: This should really be named onDuringCreate, because if it doesn't exist in the database, it doesn't exist. Half the information for any type of asset is in AssetEntry and if that data isn't valid then the object isn't really valid, is it? Wouldn't it be more useful to have a hook that fires after you have an actual object persisted to the database?

I think I've used the Message Bus hack before. I guess I was assuming that this was a bug that had been fixed and not a mis-feature.
thumbnail
Wes Kempa, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Postagens: 24 Data de Entrada: 29/07/08 Postagens Recentes
Yes, very disappointing! onAfterCreate() does not work as expected here. I guess the model itself has been created, but none of it's associations have been made at that time of initialization. I also tried the message bus to delay the load and that also did not seem to improve things any.

Here is my use case:

Client has two production servers. They post articles in one and would like some of those articles to be posted to the second server automatically. My thought was add a journal article model listener, use a custom field boolean to allow posting to second server, and use web services for the addition of the article to the second server instance - easy right? Nope, at the time of the onAfterCreate() the expando field has not been updated with the value for my boolean. After spending longer that I should have to get the message bus working in my favor, I get a "No JournalArticle exists with the primary key" for the article id sent in the message... maybe it is not there yet? SQL reveals that it is now, so timing again!

Next step for me is to scrap all and create a scheduled job that will check the JournalArticleLocalServiceUtil for new entries at a certain interval. Then I am confident I can get the expando boolean out of the transaction.

Disappointing yes, but live and learn.
thumbnail
Krzysztof Gołębiowski, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Liferay Master Postagens: 549 Data de Entrada: 25/06/11 Postagens Recentes
Hello All,
Some time ago I had a similar problem and as far as I remember, the problem was that model listeners were called when the JournalArticle was persisted for a first time using update( ... ) method. It happens in the middle of JournalArticleLocalServiceUtil.addArticle( ... ) method, and the changes do not go immediately to database as the whole addArticle method is run within a single transaction.

I solved it using MessageBus Listener with 3 seconds delay.

But... why don't you use staging, I think It would fit your requirements best.

Regards,
KG
Kevin Musarella, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Postagens: 2 Data de Entrada: 02/07/13 Postagens Recentes
Instead you should use TransactionCommitCallbackRegistryUtil which will allow you to use a callback method after the transaction is complete.

Ex:

private void reindexUserAsync(final long userId) {

	TransactionCommitCallbackRegistryUtil.registerCallback(new Callable<void>() {

		@Override
		public Void call() throws Exception {
                        // Insert whatever here
			Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(IndexablePerson.class);
			indexer.reindex(IndexablePerson.class.getName(), userId);

			return null;
		}
	});
}
</void>
thumbnail
David H Nebinger, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Liferay Legend Postagens: 14919 Data de Entrada: 02/09/06 Postagens Recentes
The whole question was really moot, if you ask me...

onAfterCreate is called after the model is created and is ready to be persisted. But with Hibernate caching, the change is not necessarily pushed to the database right away to reduce db churn. The data layer will ensure that if you query for it, whatever, the same object should come back (even when it has not yet actually been persisted, but hibernate will choose when to actually complete the persistence), but your code should be totally oblivious to it.

Unfortunately for some things, there can be a database model and a corresponding physical asset (i.e. image or document, a file, etc.). The onAfterCreate() is called because the code needs to persist the database record as well as the corresponding physical asset.

Unfortunately, onAfterCreate() does not mean that both the DB entity and physical entity have been created, just the DB record. In cases like these, sometimes devs want to use onAfterCreate to manipulate the physical entity and the code can fail.

I'm not sure how the indexing stuff got thrown in here, but ideally you'd be using a post indexing hook to manipulate what is added to the index. The register callback thing has a limited context of usability (basically a hook) due to class loader boundaries and what not.
thumbnail
Atin Agarwal, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

Junior Member Postagens: 86 Data de Entrada: 20/02/12 Postagens Recentes
I think we should be using Service Wrapper Hook instead of Model Listener Hook, to achieve this kind of functionality.

Regards,
Atin Agarwal
Kevin Musarella, modificado 9 Anos atrás.

RE: Model listeners: in onAfterCreate, the model is not yet persisted?

New Member Postagens: 2 Data de Entrada: 02/07/13 Postagens Recentes
David H Nebinger:

I'm not sure how the indexing stuff got thrown in here, but ideally you'd be using a post indexing hook to manipulate what is added to the index. The register callback thing has a limited context of usability (basically a hook) due to class loader boundaries and what not.


The indexing thing was just an exemple of my code because i needed to reindex a custom entity after team association update. That's why i needed the team to be persisted while indexing. So the TransactionCommitCallback does the trick here. In my opinion that's a good alternative solution to ServiceWrapper because the number of methods to hook could be huge and error prone, whereas Listeners only contains few method.