API Forum

This forum is in read-only mode.
Please refer to our API support in case you have any questions.
We can be reached at api@e-conomic.com
e-conomic API developer forum

Caching Currency object locally to boost performance

0
Hi.

I importing a lot of CashBookEntries and want to maximize performance, therefore I would like to cache the Currency objects locally so I don't have to request it for each of my CashBookEntries_Create. My code is working as designed, so it will only request the Currency from the server the first time a new currency is used, but when I get the daily Usage overview from you, I can see that there are performed just as many Currency_GetCode as I have created CashBookEntries

Here is my code:

private ICurrency CurrencyFind(string currencyCode)
        {
            ICurrency theCurrency = null;

            foreach (ICurrency currency in currencyList)
            {
                if (currency.Code.ToLower() == currencyCode.ToLower())
                {
                    theCurrency = currency;
                    break;
                }
            }

            if (theCurrency == null)
            {
                theCurrency = session.CurrencyData.Currency.FindByCode(currencyCode);
                currencyList.Add(theCurrency);
            }

            return theCurrency;
        }

Can I do it differently so Currency_GetCode will not be equal to CashBookEntry_CreateFromData, but only equal the number of different currencies used?

Kindly regards Rasmus
created Oct 12, 2010 by Ruffio
0% Accept Rate
Q 3 A 5 C 0

6 Answers

0
Hi,

Sure you can:

Cache the currency objects in a Dictionarystring, ICurrency once - using Code.ToLower() as the key, and the currency object as the value. Then you've got an easy way of obtaining a currency code's corresponding ICurrency object afterwards.


Best regards,
answered Oct 12, 2010 by Christian Estrup
0
Thanks for your feedback, but as I wrote my caching code works as designed, the call to session.CurrencyData.Currency.FindByCode(currencyCode) is only called once per unique currency, so if I have 100.000 entries with Currency DKK, the method is only called once, which is the first time.

The point is that when we get the Usage Overview from you we can see that there are 100.000 CashBookEntries.Create and 100.000 Currency_GetCode which you guys add up to 200.000 transactions and not 100.000... It's because you also count all the internal calls and not only those that we submit.

Kindly Regards Rasmus
answered Oct 13, 2010 by Ruffio
0
What you're doing isn't enough to cache locally:

Your cache contains ICurrency objects, which are basically proxy objects. As such, any get'er - including the Code get'er - WILL actually result in a network round-trip

The typical way of resolving this is to cache data objects instead - in this case: ICurrencyData objects.

However, since what you need to FIND in your cache is ICurrency objects, what you need in your lookup is really only to match ISO currency codes to ICurrency objects. Thus, my suggestion of caching these in a Dictionarystring, ICurrency stands.


Best regards,
answered Oct 14, 2010 by Christian Estrup
0
I found my actual problem and must correct my statement.

As I have alot of entries to add from a csv file I use a foreach loop to run thru all my entries.

The 'problem' was even though I had cached the Currency object (either by a list or dictionary, it doesn't matter) the line ICurrency actualCurrency = CurrencyFind(currencyCode); made a server call. I didn't think it would make this call to the server every time as I had already cached the object, but it does. I thought it was only calling the server when I did something like: session.CurrencyData.Currency.FindByCode(currencyCode); but I was wrong. The server is called every time the object is instantiated even though it was from a locally cached object.

The solution is to reuse a generic currency object that is only instantiated once, which is outside of the foreach loop, and then just change it accordingly to what currency is needed.

So instead of:

foreach (all my entries)
{
  ...
  ICurrency actualCurrency = CurrencyFind(currencyCode); //Get cached object, but call to server is still performed because the object is instantiated
  ..
  [find other properties such as accountnumber, vouchernumber, etc.]
  ..
  ICashBookEntryData newEntryData = session.CashBookEntryData.Create(......);
  newEntryData.Currrency = actualCurrency;
  ...
  session.CashBookEntry.CreateFromData(newEntry);
}

I do:

ICurrency actualCurrency;
foreach (all my entries)
{
  ...
  actualCurrency = CurrencyFind(string currencyCode); //Get cached object from either dictionary or list, it doesn't matter
  ..
  [find other properties such as accountnumber, vouchernumber, etc.]
  ..
  ICashBookEntryData newEntryData = session.CashBookEntryData.Create(......);
  newEntryData.Currrency = actualCurrency;
  ...
  session.CashBookEntry.CreateFromData(newEntry);
}

You see the only difference is that the Currency object is only instantiated once (and used many times, sometimes changed to another) and that's the whole difference, because a call to the server is made every time it's instantiated. It doesn't matter how the object is cached, is has nothing to do with that and it shouldn't have. But as a matter of fact, I have switched to use Dictionary as it's faster than using List.

Thanks for the help. Even though your focus was in the wrong place, you helped me find a solution, and that's what matters. Because of this I'm also using cached objects when 'binding' account to cashbookentries and the result is, that it will now only take full 8 days (importing 24 hours pr. day) instead of 20 days. Thanks for the help  
answered Oct 14, 2010 by Ruffio
0
I can assure you that purely instantiating the object doesn't round-trip !

However, as soon as you call a get'er - for example objCurrency.Code, which is basically a wrapper around the SOAP call Currency_GetCode) - it will round-trip. In the code you posted for your CurrencyFind() method, that method did just that: Access the currency object's .Code get'er.

As I mentioned, caching all currencies in a Dictionarystring, ICurrency will allow you to look up a currency object by the ISO code, without round-trips. Similar tricks can be pulled for looking up e.g. account objects by account numbers.

Believe me - I've helped quite a few developers with our integration partners optimize like this, and very frequently validated this by checking our server-side logs of corresponding SOAP calls.


Best regards,
answered Oct 14, 2010 by Christian Estrup
0
Ah ok, that explains a lot. I have never seen an architecture like this, it's not quite performance minded is it? I'm sure you have your reasons for making this architecture, and I believe you when you say that you have helped a lot of developers optimizing. It could be a good idea to make a little optimizations guide, that explains some of these things as it's not very clear in the documentation when a round trip is made. I guess it's not what is next in line as writing documentation is quite dull

Thanks for the feedback, now everything is much more clear to me
Have a good weekend.

Chears
answered Oct 15, 2010 by Ruffio
Visma e-conomic A/S
...