Exception on Create

Topics: Writing modules
Sep 6, 2011 at 3:44 PM
Edited Sep 6, 2011 at 3:45 PM

Inside a controller I am trying to create a custom part, TestimonialPart.  After the code exits the contoller create post method I am getting the following exception:

The transaction has aborted

InnerException: {"null id in Orchard.Indexing.Models.IndexingTaskRecord entry (don't flush the Session after an exception occurs)"} System.Exception {NHibernate.AssertionFailure}

The exception occurs in the line  _scope.Dispose(); in the TransactionManager.

My code in the Admin Controller is: 

 

 

        // Create
        public ActionResult Create()
        {
            var newTestimonial = _contentManager.New<TestimonialPart>("Testimonial");
            return View(newTestimonial);
        }

        [HttpPost]
        public ActionResult Create(FormCollection input)
        {
            var testimonial = _contentManager.New<TestimonialPart>("Testimonial");

            if (!TryUpdateModel(testimonial, new[] { "Comment", "Name", "Company", "Url", "BubbleSide", "LeftRightColumn" }))
            {
                return View(testimonial);
            }

            _contentManager.Create(testimonial);
            _notifier.Information(T("Testimonial created"));
            return RedirectToAction("Index");
        }    

        

 

 

 My migration file is:

 

 

 

 

 

 Any help would be greatly appreciated!

 

  

 

 

 

 

        public int Create() 
        {
			// Creating table TestimonialRecord
			SchemaBuilder.CreateTable("TestimonialRecord", table => table
				.ContentPartRecord()
				.Column("Comment", DbType.String)
				.Column("Name", DbType.String)
				.Column("Company", DbType.String)
                .Column("Url", DbType.String)
                .Column("BubbleSide", DbType.String)
                .Column("LeftRightColumn", DbType.String)
                );

            ContentDefinitionManager.AlterPartDefinition(typeof(TestimonialPart).Name, cfg => cfg.Attachable());

            return 1;
        }

        public int UpdateFrom1()
        {
            SchemaBuilder.AlterTable("TestimonialRecord", table => table
                .AddColumn("TestimonialDateUtc", DbType.DateTime)
           );
            return 2;
        }

        public int UpdateFrom2()
        {
            ContentDefinitionManager.AlterTypeDefinition("Testimonial",
               cfg => cfg
                   .WithPart("TestimonialPart")
                   .WithPart("CommonPart")
                );
            return 3;
        }

Sep 8, 2011 at 5:44 PM
Edited Sep 8, 2011 at 5:47 PM

First some background.  I am new to Orchard, but somewhat familiar with MVC.  I hope this post can help some other noob.

My first attemtpt at doing CRUD on a custom Part was above.  I have since discovered that the best practice for Parts is to 

let the Orchard ContentManager do the create and updates.  After looking through some sample code I came up with:

        
        // Create
        public ActionResult Create()
        {
            var newTestimonial = _contentManager.New<TestimonialPart>("Testimonial");
            return View(newTestimonial);
        }


        [HttpPost, ActionName("Create")]
        public ActionResult CreatePOST() 
        {
            // create testimonial content item
            var testimonialContentItem = OrchardServices.ContentManager.New("Testimonial");
            // persist (?) a content item
            OrchardServices.ContentManager.Create(testimonialContentItem);
            // update testimonial content item parts through drivers, changes will be automatically propagated to the DB
            var model = OrchardServices.ContentManager.UpdateEditor(testimonialContentItem, this);

            if (!ModelState.IsValid)
            {
                OrchardServices.TransactionManager.Cancel();
                return View((object)model);
            }

            _notifier.Information(T("Testimonial created"));
            return RedirectToAction("Index");
        }


The CreatePOST code deals with ContentItems, not ContentParts directly.  ContentItems contain ContentParts.  These Parts can be your own custom parts or parts supplied by the framework or other modules.
The key is to have your controller implement the IUpdateModel interface:
        // IUpdateModel implementation
        bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties)
        {
            return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
        }

        void IUpdateModel.AddModelError(string key, LocalizedString errorMessage)
        {
            ModelState.AddModelError(key, errorMessage.ToString());
        }


This will allow you to call OrchardServices.ContentManager.UpdateEditor
which will update your custom part as well as all of the other parts attached to your content item.
If you want to control your own schema and deal directly with your own entities, IRepository is what you want, not IContentManager.
I am still new at this.  If any of the above is incorrect, please feel free to correct me.
Thanks,
Peter