IContentManager and creating content item

Topics: Core, General, Writing modules
Mar 2, 2013 at 4:45 AM
Edited Mar 2, 2013 at 7:57 AM
I can't grasp how to use IContentManager. It is my problem: i have one ContentPart:
public class ObjectPart : ContentPart<ObjectRecord> {

        public FieldPart FieldCode
        {
            get { return Record.FieldCode; }
            set { Record.FieldCode = value; }
        }

        public FieldPart FieldName
        {
            get { return Record.FieldName; }
            set { Record.FieldName = value; }
        }
}

public class ObjectRecord : ContentPartRecord {

        public virtual FieldPart FieldCode { get; set; }

        public virtual FieldPart FieldName { get; set; }
}
Content type "MyContentType" contains content part "ObjectPart".
how can i create new instance of ObjectPart with two FieldPart fields?
i've try to make this:

handlers:
    public class FieldPartHandler : ContentHandler
    {
        public FieldPartHandler(IRepository<FieldRecord> repository)
        {
            Filters.Add(StorageFilter.For(repository));
        }
    }
    public class ObjectPartHandler : ContentHandler
    {
        public ObjectPartHandler(IRepository<ObjectRecord> repository)
        {
            Filters.Add(StorageFilter.For(repository));
        }
    }
migration.cs:
public int Create() {
        SchemaBuilder.CreateTable("ObjectRecord", table =>
                                         table.ContentPartRecord()
                                           .Column<int>("FieldCode_id")
                                           .Column<int>("FieldName_id"));

        SchemaBuilder.CreateTable("FieldRecord", table =>
                                          table.ContentPartRecord()
                                          .Column<string>("Code", c => c.WithLength(500))
                                          .Column<string>("Name", c => c.WithLength(1000))
                                          .Column<string>("DataType", c => c.WithLength(200))
                                          .Column<string>("DataValue", c => c.Unlimited()));

         ContentDefinitionManager.AlterTypeDefinition("ObjectMetadata",
                                         cfg => cfg.WithPart("ObjectPart")
                                         .WithPart("CommonPart")
                                         .Creatable()
                );
          ContentDefinitionManager.AlterTypeDefinition("FieldMetadata",
                                         cfg => cfg.WithPart("FieldPart")
                                         .WithPart("CommonPart")
                                         .Creatable()
         );
         return 1;
 }
public int UpdateFrom1() {
var meta = _contentManager.Create<ObjectPart>("MyContentType", part => {
                var field = _contentManager.New<FieldPart>("FieldPart"); //invalid cast exception here...
                field.DataValue = "test";
                field.Name = "test2";
                _contentManager.Create(field);
                var field2 = _contentManager.New<FieldPart>("FieldPart");
                field2.DataValue = "test22";
                field2.Name = "test333";
                _contentManager.Create(field2);
                part.Record.FieldCode = field;
                part.Record.FieldName = field2;
            });
 return 2;
}
but it's not working... Please help me, i cannot find the concept...
another question is how can i get ContentField that i weld to "MyContentType" contentType?
Developer
Mar 2, 2013 at 9:31 AM
You didn't show us the definition of the FieldPart class but it looks like it's a content part.
One problem that jumps out is that you defined two members on your ObjectRecord class of type FieldPart - I think that is illegal.
You should instead simply create two int properties, say:
public class ObjectRecord : ContentPartRecord {

        public virtual int FieldCodeId { get; set; }

        public virtual int FieldNameId { get; set; }
}
Then, from your ObjectPart, you could implement two LazyField<T> members that lazy load the FieldCodeId and FieldNameId.

As for your second question, you can get a content field from a content part only. So when you have a content item of "MyContentType", and you attached fields to it via the dashboard, Orchard will have created a content part called "MyContentType" as well (notice that it didn't append the "Part" suffix, this will cause the implicitly created part not to show up in the Parts list in the dashboard).
From this content part, you can access the fields. The easiest way to do it is by casting your content item to a dynamic:

``` var contentItem = _contentManager.Get(42); // load a content item of type "MyContentType"
var dynamicContentItem = (dynamic)contentItem;
var myField = dynamicContentItem.MyContentType.MyField; // the hierarchy is: contentItem.PartName.FieldName, and will return the field object, from which you can then access its properties, like Value, DateTime, etc. depending on the type of field.
Mar 2, 2013 at 10:50 AM
Edited Mar 2, 2013 at 10:51 AM
sfmskywalker wrote:
You didn't show us the definition of the FieldPart class but it looks like it's a content part.
Yes, it's primitive and contains only simple fields. I have make it simple entity, not ContentPart already.
One problem that jumps out is that you defined two members on your ObjectRecord class of type FieldPart - I think that is illegal.
You should instead simply create two int properties, say:
public class ObjectRecord : ContentPartRecord {

        public virtual int FieldCodeId { get; set; }

        public virtual int FieldNameId { get; set; }
}
Then, from your ObjectPart, you could implement two LazyField<T> members that lazy load the FieldCodeId and >FieldNameId.
Ok, thanks, i saw your great example LazyPartFieldDemo (Big thanks for this!). I'll try to make so. I thought that i can use entities field much like NHibernate.
As for your second question, you can get a content field from a content part only. So when you have a content item of "MyContentType", and you attached fields to it via the dashboard, Orchard will have created a content part called "MyContentType" as well (notice that it didn't append the "Part" suffix, this will cause the implicitly created part not to show up in the Parts list in the dashboard).
From this content part, you can access the fields. The easiest way to do it is by casting your content item to a dynamic:

``` var contentItem = _contentManager.Get(42); // load a content item of type "MyContentType"
var dynamicContentItem = (dynamic)contentItem;
var myField = dynamicContentItem.MyContentType.MyField; // the hierarchy is: contentItem.PartName.FieldName, and will return the field object, from which you can then access its properties, like Value, DateTime, etc. depending on the type of field.
Many thanks, it's really helpful for me!