access to content items field values from code

Topics: Writing modules
Oct 6, 2012 at 9:11 AM

its easy to access a content items parts from code like this :

 var contentItem = _contentManager.New(id);

contentItem.As<CommonPart>().Property;

but i dont find something similar for accessing fields from a content item instance 

 

This does not work (because it does not support IContent interface)

var dd = contentItem.As<NumericField>().Value;

 

can i get/set field values programmatically for a content item instance?

Regards

Yiannis

Developer
Oct 6, 2012 at 10:33 AM

Yes, fields are attached to parts, so if you have access to a part, you can access its fields. Each part has a Fields collection, so using a litlle LINQ you could do something like: contentItem.As<MyPart>().Fields.Where(field => field.PartFieldDefinition.Name == "MyField").Single() as TextField.

However, there's a "cleaner" way of doing it by casting your contentItem or contentPart to dynamic:

var field = ((dynamic)contentItem).MyPart.MyField;
field.Value = "Some value";

This also works great when you don't have a class defined for your part. For example, if you created a custom part called "MyCustomPart" using the admin, you can't go like contentItem.As<MyCustomPart> unless there's a class like that. So use dynamic again:

var myPart = ((dynamic)contentItem.MyCustomPart;

Oct 6, 2012 at 11:25 AM

thanks sfmskywalker,
yes i can see the fields collection that are attached to parts from the API.
But i was referring to fields related directly to the content type (not through the parts).

MyCustomContentType:

 -Fields(Collection)  --> This i cannot access through the API

 -Parts(Collection)   --> This i can access through the API

 

Developer
Oct 6, 2012 at 11:32 PM

Ah. But did you know that in reality, fields are never directly attached to the content type?
Instead, when you think you attach a field to a content type via the admin, what really happens is that Orchard creates a content part which has the same name as the content type. So for example, if you created a MyCustomContentType and attach a field to it, what really happens is that you attach the field to a content part called MyCustomContentType, which in turn is attached to the content type. So to access fields of this type, do it like this:

dynamic contentItem = ContentManager.Get( contentId );
var myField = contentItem.MyCustomContentType.MyField;

in the last line, "MyCustomContentType" is part that has been implicitly created by Orchard when you attached a field via the admin.

Oct 8, 2012 at 8:17 AM

Got it. 

Thanks Sipke.

Sep 14, 2013 at 5:53 PM
+1 for that - don't see it in the docs
Nov 7, 2013 at 3:37 PM
sfmskywalker wrote:
Yes, fields are attached to parts, so if you have access to a part, you can access its fields. Each part has a Fields collection, so using a litlle LINQ you could do something like: contentItem.As<MyPart>().Fields.Where(field => field.PartFieldDefinition.Name == "MyField").Single() as TextField. However, there's a "cleaner" way of doing it by casting your contentItem or contentPart to dynamic: var field = ((dynamic)contentItem).MyPart.MyField;field.Value = "Some value"; This also works great when you don't have a class defined for your part. For example, if you created a custom part called "MyCustomPart" using the admin, you can't go like contentItem.As<MyCustomPart> unless there's a class like that. So use dynamic again: var myPart = ((dynamic)contentItem.MyCustomPart;
I tried the above code. I could now access the field values. but when I set the field value, it don't persist in the database.
Coordinator
Nov 11, 2013 at 8:02 AM
If it doesn't persist, there is probably an exception afterwards that causes the transaction to roll back.
Nov 14, 2013 at 4:18 AM
Just encountered a similar situation. Field value is persisted in the Data column of the Orchard_Framework_ContentItemRecord table, while it should persist in Orchard_Framework_ContentItemVersionRecord (at least that's where it is stored, when field is assigned value from Admin UI).
Nov 14, 2013 at 6:57 AM
Edited Nov 14, 2013 at 6:58 AM
It looks like fields are persisted in the wrong place on initial creation of Content Item only, when their values are set before calling _orchardServices.ContentManager.Create(part.ContentItem)
However, if fields are set for an existing item, they are stored correctly.

So here is what worked in my case:
_orchardServices.ContentManager.Create(part.ContentItem);

var contentItem = _orchardServices.ContentManager.Get(part.ContentItem.Id);
if (contentItem != null)
{
    MediaLibraryPickerField fieldPDF = (MediaLibraryPickerField)((dynamic)contentItem).BibliographyPart.PDF;
    fieldPDF.Ids = new int[] { mediaPart.Id };

    _orchardServices.ContentManager.Publish(contentItem);
}
Coordinator
Nov 16, 2013 at 7:15 AM
You might want to file a bug.
Feb 14, 2014 at 4:31 PM
I'm having a similar issue. The content item I'm trying to create via code is not getting created, although I'm seeing no errors and the log doesn't have anything.
var secureMedia = _orchardServices.ContentManager.New("SecureMediaContent");

            var titlePart = secureMedia.As<TitlePart>();
            titlePart.Title = "Creating Content From Code";

            _orchardServices.ContentManager.Create(secureMedia);

            dynamic contentItem = (dynamic)_orchardServices.ContentManager.Get(secureMedia.Id);

            var field = (SecureFileField)contentItem.SecureMediaContent.SecureFile;
            var name = field.Name;
            var settings = field.PartFieldDefinition.Settings.GetModel<SecureFileFieldSettings>();
            var provider = new SecureFileStorageProvider(settings.SecureDirectoryName);

            using (FileStream fileStream
                = System.IO.File.OpenRead("C:\\Filename.pdf"))
            {
                string fileName = Path.GetFileName("C:\\Filename.pdf");
                int length = (int)fileStream.Length;
                field.Url = fileName;

                byte[] buffer = new byte[length];
                fileStream.Read(buffer, 0, length);

                provider.Insert(fileName, buffer, "application/pdf", length, true);

                _orchardServices.ContentManager.Publish(secureMedia);
            }
The file saves in the file system, but no content item is created.
Feb 18, 2014 at 3:31 PM
I was able to get it to save correctly by injecting a IRepository<ContentItemRecord> and calling the _repository.Update() method.
dynamic contentItem = (dynamic)_orchardServices.ContentManager.Get(secureMedia.Id);

var record = contentItem.Record;

_repository.Update(record);
Everything now works as it should.
Apr 18, 2014 at 3:33 AM
I have posted a bug at https://orchard.codeplex.com/workitem/20637 as it didn't appear anyone else had.
Jul 10, 2014 at 6:53 PM
+1 Very helpful thread.