This project is read-only.

Orchard field values not saved properly when item is created and published from site

Topics: Core, Customizing Orchard
Sep 19, 2013 at 1:44 PM

Wonder if anyone else has faced this problem with Orchard 1.7.

Here is the controller code to create and a new product:

var pi = _contentManager.New("Product");
pi.Parts.OfType<ProductPart>().FirstOrDefault().Name = prod["x.ProductTitle"];
pi.As<TitlePart>().Title = prod["x.ProductTitle"];
((dynamic)pi).ProductPart.ProductExpiry.DateTime = DateTime.SpecifyKind((DateTime.Parse(prod["x.ProductExpiryDate_submit"])), DateTimeKind.Unspecified);
((dynamic)pi).ProductPart.ProductStatus.Value = "Active";

Problem is all the data is saved to the part record table but the OrchardField values, i.e. DateTimeField and EnumerationField is not being saved properly.

Further digging showed that when content is published through Admin console, the field values go to Orchard_Framework_ContentItemVersionRecord as XML.

In my case, the field values are going to Orchard_Framework_ContentItemRecord.
I also changed the migrations to create ProductPartRecord table with .ContentPartVersionRecord(), but that also doesnt work.
Sep 19, 2013 at 8:00 PM
Curious why you wouldn't do pi.As<ProductPart>().Name = prod["x.ProductTitle"] ? Also, the FirstOrDefault creates a risk on null ref exception if the part isn't there. And why later you would go through dynamic to get the exact same part? Why not just store pi.As<ProductPart>() into a local variable and re-use that? Is it in order to get to a field? Then why is that a field and not a part property?
Sep 20, 2013 at 5:48 AM
Edited Sep 20, 2013 at 6:00 AM
Hi Bertand,

Thanks for helping me out. Yes, I agree it should just be pi.As<ProductPart>().Name, just as its done for title.

Is it in order to get to a field? Then why is that a field and not a part property?
And I think that's where I am conceptually wrong. I have a product part and part record, both with 3 fields: Name, SKU and Description. Since Date has to be a date picker in Orchard, its added as a DateTimeField in the migration to ProductPart and I don't have a corresponding property in the ProductPart and ProductPartRecord models.

This worked as long as a product was to be created in the CMS using Admin screen.
Now that I want to create a product using a widget, I am not able to use the ProductPart as is. So I created ProductViewModel (which has an expiryDate property) and passed it to the view like this through the Driver Display method

var y = new ViewModels.CreateProdViewModel();
        return ContentShape("Parts_CreateProdWidget",
            () => shapeHelper.Parts_CreateProdWidget(ProductDetails: y));
And since the view does not know which model its working with the validations are not working.
If I add DateTime as a property in the ProductPart itself, all the problems would be resolved.

Can you please point me in the right direction. Are you suggesting that for every Orchard field, there should be a corresponding property in the ProductPart, but not in the ProductPartRecord? Or....I should not be using Orchard fields at all and have properties in ProductPart and ProductPartRecord for DateTime and Enums?
Sep 20, 2013 at 6:22 AM
Fields and parts are supposed to be independent aspects of a content type. If you have a field that is required by a specific part, you are probably doing it wrong. Using a field just because you want the field's UI is, I'm afraid, not driven by the right motivations. All that is required by your part to function should be properties on the part. Don't forget that the site admin can always remove your fields (and that's just one of many reasons).
Sep 20, 2013 at 6:45 AM
Ok, so I should define my own datetime and enum properties and not use Orchard fields. And then handle the Orchard UI for this part in Admin template. Ok, will do that. Thanks a lot for the direction.

But then, just curious to know the use of fields if we don't want to add them to custom parts. Is this just for administrators to add fields to the parts and not meant to be used through code?
Sep 20, 2013 at 8:07 AM
Well, it is a legitimate use to add them occasionally, if it keeps that independent aspect I was talking about. For example, in my Nwazet.Commerce module, I do add a media library picker field to the product type from the migration, because more often than not, a product will have one or several photos associated with it. The image is not however assumed anywhere, and remains independent of the Product part itself. It's just that it's nice to add it as it's going to be useful in most cases, but it's perfectly fine if the administrator of the site wants to remove it (for example to replace it with some other image gallery, or who knows what). Does this make sense?
Sep 20, 2013 at 8:23 AM
Makes sense, I cant just assume that field will always be there. So if a product must have an expiry date, its better to create it as a property and not use OrchardFields which can be removed.

Another road block:
For the product part, if I override the Display, it would be to display details for a product in context, correct?

I want to create a widget that allows creation of a new product. For this I had to create ProductWidgetPart and ProductWidgetPartRecord, both of which have no fields. This has to be created, even if without properties, as this is an Orchard convention. So, the driver for the product widget would again get a part with no fields. Is it ok to just pass the ProductPart instead of the ProductWidgetPart in the ProductWidgetDriver, since the validations and all should be from ProductPart.

Or would it make sense to add WidgetPart to Product content type. But this would display details of product. I want to show a view that allows creation of products.
Sep 20, 2013 at 8:49 AM
How would you "pass the ProductPart"? Where does it come from?
Sep 20, 2013 at 9:34 AM
Edited Sep 20, 2013 at 10:02 AM
Exactly, I have no clue on how to proceed with this. Can you please point me in the right direction...
Sep 20, 2013 at 10:58 AM
Would it make sense, that I add fields to ProductWidgetPart and ProductWigetPartRecord, not link it to repository in handler. So the settings dont get saved to DB. And override the display method to pass the ProductWidgetPart which has all the properties to match the ProductPart?

This way I have two parts and part records: ProductPart and ProductPartRecord which is mapped to DB table AND ProductWidgetPart and ProductWidgetPartRecord, not linked to repository. Both Parts have the same set of validations. For productPart, Display template is overridden to show product details and ProductWidgetPartRecord is used to create a Product.
Sep 20, 2013 at 5:49 PM
I'm sorry, I don't understand at all what you mean. Seems like the display method could simply create the shape for the creation form. The editor post method would simply create the new product using the content manager based on the posted data.
Sep 23, 2013 at 6:25 AM
Hi Bertrand,

Found the solution here:

This is what I needed and its working now.