Results 1 to 8 of 8

Thread: InvalidateCache with key wildcards

  1. #1
    Join Date
    Apr 2007
    Posts
    20

    Default InvalidateCache with key wildcards

    Hi,

    we just started using spring aop caching in our application and i'm wondering if there's more documentation for it then this: http://www.springframework.net/doc-l...caching-aspect.

    Especially I am wondering how to invalidate more then one cache item at the same time.

    Simple example: we have email templates (MessageTemplate object) that have a body and subject text in different locales. These texts are stored in an object called 'Description'.

    We have a load method that loads a description for a certain template and locale, the result of this method we cache.

    Code:
    		[CacheResult(SpringCacheController.DescriptionCacheName,
    			@"'boDescriptionId=' + #_messageTemplate.BoTranslationIdBody + '_locale=' + #_locale.Id")]
    		public Description LoadLocalizedMessageTemplateBody(MessageTemplate _messageTemplate, Locale _locale)
    		{
    			IConditionBuilder conditionBuilder = PersistenceTemplate.CreateConditionBuilder();
    			conditionBuilder.AddANDStatement("boDescriptionId", _messageTemplate.BoTranslationIdBody, "=");
    			conditionBuilder.AddANDStatement("tbLocale_ID", _locale.Id, "=");
    
    			Description retVal = PersistenceTemplate.LoadObjectByConditional(typeof(Description), conditionBuilder) as Description;
    
    			return retVal;
    		}
    Now we have a Delete method, that deletes all Descriptions for a messagetemplate. Currently we need to Invalidate the whole Cache here:

    Code:
    		[InvalidateCache(SpringCacheController.DescriptionCacheName)]
    		public void DeleteMessageTemplateDescriptions(MessageTemplate _messageTemplate)
    		{
    			... build delete statement ...
    
    			PersistenceTemplate.ExecuteNonQuery(CommandType.Text, commandText, conditionBuilder.Parameters);
    		}
    Actually it would be sufficient to invalidate all CacheItems where the key starts with

    'boDescriptionId=' + #_messageTemplate.BoTranslationIdBody
    or
    'boDescriptionId=' + #_messageTemplate.BoTranslationIdSubject

    I was not able to find out how to do that. Another example would be to invalidate all cache items for a certain locale, that means the key would have to contain '_locale=' + #_locale.Id

    Any assistance on this would be greatly appreciated.

  2. #2
    Join Date
    Jul 2010
    Posts
    245

    Default

    I believe that you can achieve what you're after with a combination of the [InvalidateCache(...)] attribute and using Spring Expression Language (SPeL) to leverage wildcards to define the keys to invalidate.

    See http://www.springframework.net/doc-l...ons-relational for more info on how to build a SPeL expression that uses REGEX to match values based on wildcards. As you can see from the definition of the [InvalidateCache(...)] attribute, the attribute takes a SPeL expression here https://github.com/SpringSource/spri...tribute.cs#L91 which defines the cache keys to evict.

    I believe that combining these two should permit you to achieve what you're trying to accomplish. Let us know if this helps.

    -Steve B.

  3. #3
    Join Date
    Apr 2007
    Posts
    20

    Default

    I had a brief look a that already, but I was not sure how to write that SPeL properly. I will look into that again and play with it. I'll let you know if I can find a solution.

    But we actually ran into a massive problem in the meantime, which is currently stopping us from using spring AOP caching. And that makes me really sad, because it has a lot of potential regarding boosting our applications performance.

    I simplified the above example a bit, actually it looks like this:

    Code:
    		[CacheResult(SpringCacheController.DescriptionCacheName,
    			@"'boDescriptionId=' + #_messageTemplate.BoTranslationIdBody
    				+ '_mandator=' + #_messageTemplate.mandator.Id 
    				+ '_locale=' + #_locale.Id")]
    		public Description LoadLocalizedMessageTemplateBody(MessageTemplate _messageTemplate, Locale _locale)
    As you can see for cache key generation we use the nested Property "_messageTemplate.mandator.Id". Now our problem is, that we use a PersistenceLayer that supports lazy loading and therefore sometimes the Mandator property will be of type 'Mandator' sometimes 'MandatorGenerated'. Unfortunately spring caches the property infos of all nested properties, so if we first call the method with a MandatorGenerated and afterwards with a Mandator object, we will get the following exception:

    Code:
    Das Objekt des Typs "FirstAnswer.Support.MessageTemplate" kann nicht in Typ "FirstAnswer.Support.MessageTemplateGenerated" umgewandelt werden.
    
    Ausnahmedetails: System.InvalidCastException: Das Objekt des Typs "FirstAnswer.Support.MessageTemplate" kann nicht in Typ "FirstAnswer.Support.MessageTemplateGenerated" umgewandelt werden.
    
    Quellfehler:
    
    Zeile 299:		public Description GetMessageTemplateSubject(MessageTemplate _currentMessageTemplate, Locale _selectedLocale)
    Zeile 300:		{
    Zeile 301:			return messageTemplateDAO.LoadLocalizedMessageTemplateSubject(_currentMessageTemplate, _selectedLocale);
    Zeile 302:		}
    Zeile 303:
    
    
    Quelldatei: D:\SVN\1stAnswer5.4\FirstAnswer.Core\Service\DefaultImplementation\MessageTemplateManager.cs    Zeile: 301
    
    Stapel├╝berwachung:
    
    [InvalidCastException: Das Objekt des Typs "FirstAnswer.Support.MessageTemplate" kann nicht in Typ "FirstAnswer.Support.MessageTemplateGenerated" umgewandelt werden.]
       _dynamic_FirstAnswer.Support.MessageTemplate.get_Mandator(Object , Object[] ) +56
       Spring.Expressions.PropertyValueAccessor.Get(Object context) +62
       Spring.Expressions.PropertyOrFieldNode.GetPropertyOrFieldValue(Object context, EvaluationContext evalContext) +86
       Spring.Expressions.PropertyOrFieldNode.Get(Object context, EvaluationContext evalContext) +281
       Spring.Expressions.Expression.Get(Object context, EvaluationContext evalContext) +100
       Spring.Expressions.OpADD.Get(Object context, EvaluationContext evalContext) +164
       Spring.Expressions.OpADD.Get(Object context, EvaluationContext evalContext) +135
       Spring.Expressions.OpADD.Get(Object context, EvaluationContext evalContext) +135
       Spring.Aspects.Cache.CacheResultAdvice.GetReturnValue(IMethodInvocation invocation, CacheResultAttribute resultInfo, IDictionary vars, Boolean& cacheHit) +176
       Spring.Aspects.Cache.CacheResultAdvice.Invoke(IMethodInvocation invocation) +143
       Spring.Aop.Framework.AbstractMethodInvocation.Proceed() +335
       Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Invoke(Object proxy, Object target, Type targetType, MethodInfo targetMethod, MethodInfo proxyMethod, Object[] args, IList interceptors) +230
       CompositionAopProxy_18c5807ae5e2423794d8b28fc3642b1d.LoadLocalizedMessageTemplateSubject(MessageTemplate _messageTemplate, Locale _locale) +265
       FirstAnswer.Service.DefaultImplementation.MessageTemplateManager.GetMessageTemplateSubject(MessageTemplate _currentMessageTemplate, Locale _selectedLocale) in D:\SVN\1stAnswer5.4\FirstAnswer.Core\Service\DefaultImplementation\MessageTemplateManager.cs:301
       _dynamic_FirstAnswer.Service.DefaultImplementation.MessageTemplateManager.GetMessageTemplateSubject(Object , Object[] ) +236
       Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments) +80
       Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint() +133
       Spring.Transaction.Interceptor.TransactionInterceptor.Invoke(IMethodInvocation invocation) +367
       Spring.Aop.Framework.AbstractMethodInvocation.Proceed() +335
       Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Invoke(Object proxy, Object target, Type targetType, MethodInfo targetMethod, MethodInfo proxyMethod, Object[] args, IList interceptors) +230
       CompositionAopProxy_7f4c528157c24479a59dd52e55338386.GetMessageTemplateSubject(MessageTemplate _currentMessageTemplate, Locale _selectedLocale) +265
    The error message says, that MessageTemplate cannot be casted to MessageTemplateGenerated, but we debugged Spring and found out, that the actual error occurs in the nested property Mandator, which Spring tries to cast to MandatorGenerated.

    Is there any solution to this issue? I think this could also happen with normal inherited types, not just with our persistence layer, but i'm not sure about that.

  4. #4
    Join Date
    Jan 2006
    Location
    Cambridge, UK
    Posts
    1,340

    Default

    Hi Torsten,

    it'd be great if you run the code with the pdb's in place so that we get the line numbers

    It's been a while since I wrote this code so I can't tell from the top of my head Here are a few quick thoughts:

    is "_messageTemplate.mandator" a field? Try using a property accessor instead.
    try putting the property you are trying to access on an interface

    hth,
    Erich

  5. #5
    Join Date
    Apr 2007
    Posts
    20

    Default

    Hi Erich,

    thanx for your answer, unfortunately I just saw it. Here the stacktrace with line numbers:

    Code:
    [InvalidCastException: Das Objekt des Typs "FirstAnswer.Domain.Description" kann nicht in Typ "FirstAnswer.Domain.DescriptionGenerated" umgewandelt werden.]
       _dynamic_FirstAnswer.Domain.Description.get_mandator(Object , Object[] ) +56
       Spring.Expressions.PropertyValueAccessor.Get(Object context) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\PropertyOrFieldNode.cs:576
       Spring.Expressions.PropertyOrFieldNode.GetPropertyOrFieldValue(Object context, EvaluationContext evalContext) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\PropertyOrFieldNode.cs:299
       Spring.Expressions.PropertyOrFieldNode.Get(Object context, EvaluationContext evalContext) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\PropertyOrFieldNode.cs:229
       Spring.Expressions.Expression.Get(Object context, EvaluationContext evalContext) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\Expression.cs:277
       Spring.Expressions.OpADD.Get(Object context, EvaluationContext evalContext) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\OpADD.cs:62
       Spring.Expressions.OpADD.Get(Object context, EvaluationContext evalContext) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\OpADD.cs:60
       Spring.Expressions.OpADD.Get(Object context, EvaluationContext evalContext) in l:\projects\spring-net\trunk\src\Spring\Spring.Core\Expressions\OpADD.cs:60
       Spring.Aspects.Cache.InvalidateCacheAdvice.AfterReturning(Object returnValue, MethodInfo method, Object[] arguments, Object target) in l:\projects\spring-net\trunk\src\Spring\Spring.Aop\Aspects\Cache\InvalidateCacheAdvice.cs:115
       Spring.Aop.Framework.Adapter.AfterReturningAdviceInterceptor.Invoke(IMethodInvocation invocation) in l:\projects\spring-net\trunk\src\Spring\Spring.Aop\Aop\Framework\Adapter\AfterReturningAdviceInterceptor.cs:93
    "_messageTemplate.mandator" is a Property:

    Code:
    		[PersistentProperty("tbMandator_ID", Type = PersistentProperty.FK)]
    		public virtual Mandator Mandator
    		{
    			get;
    			set;
    		}
    And currently our domain objects do not have an interface. So if that would be the solution it would mean major changes to our application.

    Hopefully you have another idea ;-)

    Regards,
    Torsten

  6. #6
    Join Date
    Jan 2006
    Location
    Cambridge, UK
    Posts
    1,340

    Default

    tried using uppercase "Mandator" already?

  7. #7
    Join Date
    Apr 2007
    Posts
    20

    Default

    just now, doesn't make a difference. but we are able to replicate it with a nunit test and our spring config, if that helps.

  8. #8
    Join Date
    Apr 2007
    Posts
    20

    Default

    I removed pretty much all unnecessary code and have a simple nunit test that produces the above described error.

    The project can be dowloaded here:

    http://tliebscher.free.fr/SpringCachingTest.rar

    It would be great if you could have a quick look at it.

    Regards,
    Torsten

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •