Problem saving data in other languages by api

Vote:
 

Hi, we have a scheduled jobs which imports airport data from a external webservice, the job it selfs works fine, but we see something strange.

 

When i save an airport in an other language than english (which is the master language), the fields who are exact the same as the master language are not saved.....

 

Ie when i in English the city is named: Amsterdam, and in German also Amsterdam, the field is not saved and keeps blanc in the CMS, but when i would save the german version as: Hey this is Amsterdamnia the save seems to be correct and is shown in the CMS.

At first i thought this is maybe by design and that the field who return at a frontend call, but there it is also empty.....

Can someone tell me or this is a bug in CMS 6 (R1).

The code i Use:

 

        private void UpsertAirport(FeatureAirportPT airport, City city , string locale)
        {
            airport.PageName = city.AirportCode.Trim();
            airport.AirportCode = city.AirportCode.Trim();
//          airport.AirportName = city.AirportName.Trim() + " " + locale;
            airport.AirportName = city.AirportName.Trim();

            airport.CityName = city.CityName.Trim();
            airport.Country = city.CountryName.Trim();
            DataFactory.Instance.Save(airport, SaveAction.Publish);

    

#66878
Mar 11, 2013 17:35
Vote:
 

Is this only happening for built in properties or for properties defined in your typed page?  Can you try something once.  Can you try   
airport.setValue("propertyName","value");  just curious if it is strongly typed property issue or all together a saving of a language branch.

#66881
Mar 12, 2013 0:05
Vote:
 

Hi Joshua when i was biking to my work tomorrow i had the same idea ;)

I tested it, but it doesn't make a difference.

FeatureAirportPT is in fact strong typed by using PageType Builder.

When i use: airport.SetValue("AirPortname", city.AirportName.Trim() + " " + locale); it is inserted correctly, so this seems to be a bug in the API ;(

I am thinking about a small hack by prefixing the locale with the actual value, and strip it away in the Getter, definitly not very clean...

 

 

#66887
Mar 12, 2013 9:24
Vote:
 

Mmmmm this is quite frustrating, especially because there is not really a clean workaround, can someone from Epi Server support tell me or this is a know bug?

#67813
Mar 13, 2013 10:19
Vote:
 

wWthout having looking into the code in detail, perhaps the case is that the propertydata already contains the value for master language (for some reason). Then when you set the value the property will detect that the value is the same as it already have and hence it will not be marked as modified and therfore not saved either...

If that is the case then a workaround would be to explicitly call

propertyDataInstance.IsModified = true;

before saving the page.

#67835
Mar 13, 2013 14:37
Vote:
 

Hi Johan thanks for your suggestion, i did try that but it doesn't seems to make a difference, i was thinking about the same, but even when that is true, that means that in this logica the languagebranch is skipped, which seems wrong to me.

#67852
Mar 13, 2013 15:46
Vote:
 

I guess I am not sure why you wouldn't just use the setValue method.  Are you by chance using PageTypeBuilder?

#67854
Mar 13, 2013 15:54
Vote:
 

Yes i use PageTypeBuilder, but also when i use set value the value is not updated...

#67855
Mar 13, 2013 15:56
Vote:
 
#67857
Mar 13, 2013 16:02
Vote:
 

Can you post your code where you are actually instantiating the object that you are passing into this method.

#67859
Mar 13, 2013 16:03
Vote:
 

Ok This is the complete code:

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using EPiServer;
using EPiServer.BaseLibrary.Scheduling;
using EPiServer.Core;
using EPiServer.DataAccess;
using EPiServer.PlugIn;
using EPiServer.Security;
using log4net;
using PageTypeBuilder;
using SkyTeam.Business.Cms;
using SkyTeam.Business.Cms.PageTypes.Data;
using SkyTeam.Business.Cms.PageTypes.Data.Containers;
using SkyTeam.Business.Cms.PageTypes.Data.Features;
using SkyTeam.Business.Service;
using SkyTeam.Business.MultiLingualService;
using System.Globalization;

namespace SkyTeam.Business.Jobs
{
    [ScheduledPlugIn(DisplayName = "City list Import", Description = "This job imports city list from GoldenWare")]
    public class CityListImport : JobBase
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(CityEventsImport));
        public CityListImport()
            : base()
        {
            // Make the job interruptable
            this.IsStoppable = true;
        }

        public override string Execute()
        {
            int pageTypeAirportID = PageTypeResolver.Instance.GetPageTypeID(typeof(FeatureAirportPT)).Value;
            int pageTypeCountryID = PageTypeResolver.Instance.GetPageTypeID(typeof(CountryPT)).Value;
            
            IEnumerable<CountryPT> countries;
            IEnumerable<FeatureAirportPT> airports;
            CountryContainerPT countryContainerPT;
            
            MultiLingualClient client = new MultiLingualClient();
            foreach (KeyValuePair<string,string> serviceLocale in MultiLingualServiceHelper.ServiceLocales)
            {
                countries = PageUtilities.GetCountries("en");
                // The english list of airports is the master list
                // NOTE: This statement can not be placed outside the foreach, extra added airports in english list won't be found in lists of other languages
                // NOTE2: "en" should not be replaced with serviceLocale.Key because that will result in separate country item per language
                airports = PageUtilities.GetAirports("en");
                countryContainerPT = PageUtilities.GetPagesOfType<CountryContainerPT>().First();

                GetCitiesResponse cities = client.GetCities(serviceLocale.Value);

                //Handig om set te beperking tijdens test
              // foreach (City city in cities.Cities.Where(X => X.CityName == "Amsterdam"))
               foreach (City city in cities.Cities)
                {
                    CountryPT country = null;
                    FeatureAirportPT airport = null;
                    try
                    {
                        country = countries.FirstOrDefault(c => !string.IsNullOrWhiteSpace(c.CountryCode) && c.CountryCode.Trim().ToUpper() == city.CountryCode.Trim().ToUpper());
                        if (country == null)
                        {
                            // Only create a new country for the english language, otherwise orphans will be created
                            if (serviceLocale.Value.Equals("en", StringComparison.OrdinalIgnoreCase))
                            {
                               country = (CountryPT)DataFactory.Instance.GetDefaultPageData(countryContainerPT.PageLink, pageTypeCountryID);
                            }
                        }

                        if (country != null)
                        {
                            CountryPT countryClone = (CountryPT) country.CreateWritableClone();
                            countryClone.ParentLink = countryContainerPT.PageLink;
                            countryClone.LanguageID = serviceLocale.Key;

                            UpsertCountry(countryClone, city,serviceLocale.Value);

                            airport = airports.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.AirportCode) && a.AirportCode.Trim().ToUpper() == city.AirportCode.Trim().ToUpper());

                            if (airport == null)
                            {
                                // Only create a new airport for the english language, otherwise orphans will be created
                                if (serviceLocale.Value.Equals("en", StringComparison.OrdinalIgnoreCase))
                                {
                                    airport = (FeatureAirportPT)DataFactory.Instance.GetDefaultPageData(country.PageLink, pageTypeAirportID);
                                }
                            }

                            if (airport != null)
                            {
                                FeatureAirportPT airportClone = (FeatureAirportPT) airport.CreateWritableClone();
                                airportClone.ParentLink = country.PageLink;
                                airportClone.LanguageID = serviceLocale.Key;

                                UpsertAirport(airportClone, city, serviceLocale.Value);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Fatal(string.Format("{0},{1}", ex.Message, ex.InnerException));
                    }
                }
            }

            return "Processing citylist successful";
        }

        private void UpsertAirport(FeatureAirportPT airport, City city , string locale)
        {
            airport.PageName = city.AirportCode.Trim();
            airport.AirportCode =  city.AirportCode.Trim();
            airport.AirportName = city.AirportName.Trim();
            airport.CityName =city.CityName.Trim();
            airport.Country = city.CountryName.Trim();

            airport.IsModified = true;
            DataFactory.Instance.Save(airport, SaveAction.Publish, AccessLevel.Publish);
        }

        private void UpsertCountry(CountryPT country, City city, string locale)
        {
            country.PageName = city.CountryName.Trim();
            country.CountryCode = city.CountryCode.Trim();
            country.CountryName = city.CountryName.Trim();

            country.IsModified = true;
            DataFactory.Instance.Save(country, SaveAction.Publish);
        }

        private string Prefix(string value, string prefix)
        {
           return string.Concat(prefix, "|", value);
        }
    }



}

    

#67860
Edited, Mar 13, 2013 16:04
Vote:
 

I know this may sound kind of weird but could you try removing the Cast on this line
(FeatureAirportPT)DataFactory.Instance.GetDefaultPageData(country.PageLink, pageTypeAirportID);

and just pass into your UpsertAirport (PageData airport)
then use setvalues on the pagedata. 

#67866
Mar 13, 2013 16:32
Vote:
 

The "normal" way of create a new language branch is to use DataFactory.Instance.CreateLanguageBranch (compared to clone the master language). If you use CreateLanguageBranch then properties that are LanguageSpecific will not have any values on your instance (while they will have the value from master if you use clone).

#67867
Mar 13, 2013 16:44
Vote:
 

@Joshua, did try it with PageData instead of FeatureAirPortPT, too bad that doesn't work too.

@Johan, i don't get it, the fact that when i use an other input string as the english one, it works perfect, to be clear:

 

If the english page field of cityname is "Amsterdam" and i insert in the German version: "Amsterdam" the field is empty in the German version.

When i instead insert "DL|Amsterdam" the field is updated/inserted correctly, so i would expect that the way i update and save the Page is correct.

#67871
Mar 13, 2013 17:16
Vote:
 

I think the reason is that the PropertyData instance that is backing the data will recognize that the value you set is the same as it already has and hence it will ignore the set operation and the property will still be marked as NotModified (which will lead to that the value is not saved to db).

If I am correct then use of CreateLanguageBranch instead of clone would solve your problem since then the property would not have a previous value and hence it would be set and marked as modified. An alternative is to force the property to be marked as modified.

If you run your job under a debugger can you look at the backing PropertyData instance before the save call and see what the value of IsModified is?

#67872
Mar 13, 2013 17:23
Vote:
 

Hi Johan, i did do a check, the isModified = false on english (as espected, since the data was the same), for the german version the isModified = true, i did also a doublecheck on the property value, as you can see on the screenshot, you can see that the data is correct.

http://oi49.tinypic.com/27xi0qu.jpg

Can it be that this thread is related?

http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=35505&

#67873
Edited, Mar 13, 2013 18:01
Vote:
 

If you look at the property in your debug screenshot you can see that even though

page.IsModified=true

you see that

property.IsModified = false

this means the value of the property will not be saved to db. You need to explicitly set IsModified=true on the property to force it to be saved. 

#67892
Mar 14, 2013 9:16
Vote:
 

Ah thx Johan, i overlooked that, thought the isModified only existed on the page level, i will give it a try, will let you know or that solves the problem.

#67896
Mar 14, 2013 9:34
Vote:
 

I think i found out what the problem was, our PageType has a mix of uniquevalues per language, and non unique values, if you insert a page where the value is not unique per language, this will result in a database error.

I also had to build in a check, or the page already exists for a language branch, finally i got this piece of code which is working:

 

private void UpsertAirport(PageData airport, City city , string locale)
{

PageData pageDataToInsert;
if (DataFactory.Instance.GetPage(airport.PageLink, new LanguageSelector(airport.LanguageID)) == null)
{
pageDataToInsert = DataFactory.Instance.CreateLanguageBranch(airport.PageLink, new LanguageSelector(airport.LanguageID));
}
else
{
pageDataToInsert = DataFactory.Instance.GetPage(airport.PageLink,new LanguageSelector(airport.LanguageID));
}

PageData pageDataToInsertWritableClone = pageDataToInsert.CreateWritableClone();
pageDataToInsertWritableClone.PageName = city.AirportCode.Trim();

pageDataToInsertWritableClone.SetValue("AirportName", city.AirportName);
pageDataToInsertWritableClone.Property["AirportName"].IsModified = true;

pageDataToInsertWritableClone.SetValue("CityName", city.CityName);
pageDataToInsertWritableClone.Property["CityName"].IsModified = true;

pageDataToInsertWritableClone.SetValue("Country", city.CountryName);
pageDataToInsertWritableClone.Property["Country"].IsModified = true;
pageDataToInsertWritableClone.IsModified = true;
var saveResult = DataFactory.Instance.Save(pageDataToInsertWritableClone, SaveAction.Publish, AccessLevel.Publish);
}

#67991
Mar 14, 2013 14:24
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.