PropertyList on catalog content items

Vote:
 

We need to save store specfic data (80+ stores) on our product and variant items. The data needs to be queryable (through Find) and editable by commerce editors.

At the moment we are using PropertyList to store the data, but there seems to be some issues related to this, ref:

https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2016/2/propertylist-not-working---can-not-be-mapped-to-a-metadatatype/

Do you plan to fully support PropertyList type in Commerce? Any other suggestions on how to solve this?

#182752
Sep 28, 2017 15:05
Vote:
 

In addition to what Mari said:

We tried to add BackingType with an implementation of the PropertyList<>. We can't see that it's triggering the ParseItem-code in our implementation (Like it does on the CMS).

What we are experiencing is that the serialized data we get in the Commerce-database (CatalogContentProperty) is not the same as we get when reading data through the contentRepository. The difference is on decimals, where we on the input have a precision of 5 decimals (which is also in the database) but when we retieve the data - we only have a precision of 0 decimal in the objects.

#182756
Sep 28, 2017 15:30
Vote:
 

I might be out of date here (slightly), but the PropertyList should work fine as long as you specify the correct backing type. It'll be slightly revised in CMS 11, but I don't remember it being broken or not working ... 

And yes we fully support PropertyList, so if anything is not working, let us know and we will look into it.

#182758
Sep 28, 2017 15:37
Vote:
 

According to this: https://world.episerver.com/support/Bug-list/bug/COM-2394 PropertyList was supported as of Commerce 9.22.

But yes, we are experiencing some issues, see the comment from @Thomas above.

#182772
Sep 28, 2017 20:56
Vote:
 

If you can provide more detail (test code to reproduce the problem), we will make sure to look into it 

#182774
Sep 28, 2017 21:22
Vote:
 

Hi Quan, 

I used the Quicksilver-site to recreate the problem. 

The model with a propertylist:

    [CatalogContentType(
        GUID = "c1bc1c4e-4a46-4a03-8e90-71bec3576aff",
        MetaClassName = "FashionVariant",
        DisplayName = "Fashion Variant",
        Description = "Display fashion variant")]
    public class FashionVariant : VariationContent
    {
        [Searchable]
        [Tokenize]
        [IncludeInDefaultSearch]
        [BackingType(typeof(PropertyString))]
        [Display(Name = "Size", Order = 1)]
        public virtual string Size { get; set; }

        [Searchable]
        [CultureSpecific]
        [Tokenize]
        [IncludeInDefaultSearch]
        [BackingType(typeof(PropertyString))]
        [Display(Name = "Color", Order = 2)]
        public virtual string Color { get; set; }

		[BackingType(typeof(TestItemProperty))]
		public virtual IList<TestItem> TestItems { get; set; }

    }

	public class TestItem
	{
		public decimal DecimalValue { get; set; }
	}
	
	[PropertyDefinitionTypePlugIn]
	public class TestItemProperty : PropertyList<TestItem>
	{
		private Injected<ObjectSerializerFactory> _objectSerializerFactory;
		private IObjectSerializer _objectSerializer;

		public TestItemProperty()
		{
			_objectSerializer = this._objectSerializerFactory.Service.GetSerializer("application/json");

		}

		public override PropertyData ParseToObject(string value)
		{
			ParseToSelf(value);
			return this;
		}

		protected override TestItem ParseItem(string value)
		{
			var testItem = _objectSerializer.Deserialize<TestItem>(value);

			return testItem;
		}
	}

The code the code that runs:

			FashionVariant newVariant = _contentRepository.GetDefault<FashionVariant>(ContentReference.StartPage);
			newVariant.Name = "MyTest";
			newVariant.Code = "MyTestCode";
			newVariant.TestItems = new List<TestItem>();
			newVariant.TestItems.Add(new TestItem());
			newVariant.TestItems[0].DecimalValue = 1.0000000000m;

			var contentLink = _contentRepository.Save(newVariant, SaveAction.Publish, AccessLevel.NoAccess);

			var afterRead = _contentRepository.Get<FashionVariant>(contentLink);

			var string1 = newVariant.Property["TestItems"].ToRawString();
			var string2 = afterRead.Property["TestItems"].ToRawString();

Result:
string1 = [{"decimalValue":1.0000000000}]
string2 = [{"decimalValue":1.0}]

So the precision level has changed. This causes problem for us when comparing objects. 

In the CatalogContentProperty-table in the database, the value is stored like this:
[{"decimalValue":1.0000000000}]

#182840
Edited, Sep 29, 2017 9:59
Vote:
 

I'm guessing here, but my gut says that this is likely a JsonSerializer problem than the PropertyList itself ...

#182841
Sep 29, 2017 10:02
Vote:
 

The behavior should be the same for the type whether it's used on a cms content type or a catalog content type. Right now, they behave different (as described above). And also, BackingType is required for catalog content types.

#182844
Sep 29, 2017 10:12
Vote:
 

Another thing, is that I did a little test:

I added this code to the TestItemProperty:

		protected override TestItem ParseItem(string value)
		{
			var testItem = _objectSerializer.Deserialize<TestItem>(value);

			testItem.DecimalValue = 999999.999m;

			return testItem;
		}

I would expect the Deserializer to run, and always return 999999.999, but when I look at the objects, the value is still 1. So, is it using another mechanism here?

#182845
Sep 29, 2017 10:15
Vote:
 

string2 = [{"decimalValue":1.0}]

So the precision level has changed. This causes problem for us when comparing objects. 

In the CatalogContentProperty-table in the database, the value is stored like this:
[{"decimalValue":1.0000000000}]

=> This should be because of the Deserializer which does not respect the precision. 

"I would expect the Deserializer to run, and always return 999999.999, but when I look at the objects, the value is still 1. So, is it using another mechanism here?"

=> Not sure I understand this. You set the value after the deserializer has run, right? Did you mean testItem still have value of 1.0? 

#182860
Sep 29, 2017 10:43
Vote:
 

1. Yes. The deserializer did not respect the precision.

2. Yes. I set the value after the deserializer, and the testItem still has value 1.0. Seems like it does not use the property in the backing type.

If I do the following with the JSON.net serializer:

TextReader textReader = new StringReader("[{\"decimalValue\":1.0000000000}]");
JsonReader reader = new JsonTextReader(textReader);

var serializer = new Newtonsoft.Json.JsonSerializer();
var o = serializer.Deserialize(reader);

TextWriter writer = new StringWriter();
serializer.Serialize(writer, o);

string value = writer.ToString();


Value will be:&nbsp;[{\"decimalValue\":1.0}]&nbsp;



I have a gut feeling (without having tested it) that this happens when you deserialize the object without specifying the type. (I may be completely wrong here. :D)

#182887
Edited, Sep 29, 2017 11:55
Vote:
 
  1. There is a very little (if anything) we can do. Perhaps you can update your comparer to ignore the precision difference?
  2. PropertyList has some methods which call each other. It's getting revised now, so I'm not sure, but I think your change might not be correct or enough. 
#182888
Sep 29, 2017 11:58
Vote:
 

I am interested to know if anyone has gotten this to work? The thread that is referenced in the bug isn't really clear on how exactly it was fixed. I have tried a few different backing types for my property to no avail. I was able to work around the issue by creating a block with my repeatable property and adding it as to a content reference on my variant. It works, but, it creates an extra layer that wouldn't be needed if the property could simply exist on the variant. It would be great if this could get fixed, or, if it is possible now, there was some solid documentation written on how to use it properly. 

#184661
Nov 01, 2017 15:39
Vote:
 
[BackingType(typeof(PropertyLongString))]

That works for me

#185049
Nov 08, 2017 19:51