n-n relationship better understanding, please!

Topics: Writing modules
Feb 17, 2011 at 12:30 AM

I am starting to confuse myself, so if i confuse you.  I apologize!

I have two records Program and Belt. I have built a list of belts and need to associate a program to multiple belts. Each program can have multiple belts. Similar to the rewards.  I have been reading and following the Rewards sample, as much as I can at this time.  

I am having a disconnect where customer comes in and entered into the relation and db. 

As of now, I have everything populating into the ui correctly. I can see the radiobuttons for Belts and there respective name.  When I save the Program with selected belts, I am receiving an error.

"attempted to assign id from null one-to-one property: ContentItemRecord". This is coming from my service function called

UpdateBeltsForContentItem, under the foreach loop (var belt in lookupNew.Where(r => !r.Value).Select(r => r.Key)). The var record variable is enumerating as empty. I have also attempted to create a new program and save, but I still receive the same error.

 public void UpdateBeltsForContentItem(ContentItem item, IEnumerable belts){
            var record = item.As<BeltsPart>().Record;
            var oldBelts = _contentBeltRepository.Fetch(
                r => r.BeltsRecord == record);
            var lookupNew = belts
                .Where(e => e.IsChecked)
                .Select(e => e.Belt)
                .ToDictionary(r => r, r => false);
            foreach (var contentBeltProgram in oldBelts)
            {
                if (lookupNew.ContainsKey(contentBeltProgram.BeltRecord))
                {
                    lookupNew[contentBeltProgram.BeltRecord] = true;
                }
                else
                {
                    _contentBeltRepository.Delete(contentBeltProgram);
                }
            }
            foreach (var belt in lookupNew.Where(r => !r.Value).Select(r => r.Key))
            {
                _contentBeltRepository.Create(new ContentBeltProgramsRecord
                {
                    BeltsRecord = record,
                    BeltRecord = belt
                });
            }
        }

Coordinator
Feb 17, 2011 at 12:40 AM

Ìf I had to make a blind guess I'd say something in the migration is wrong. But with just this error message and that piece of code it's very hard to say. Did you attach a debugger in order to inspect the content item when that exception is thrown?

Feb 17, 2011 at 2:40 AM

Yep, I attached the debugger to get the error and where it was originating.  I had errors in the migration and fixed those issues.  

The ContentItem is coming back as the Program entity. Here is more code.  I appreciate the help in trying to understand Orchard better.

public class BeltsPart:ContentPart
    {
        public IEnumerable Belts
        {
            get { return Record.Belts.Select(r => r.BeltRecord); }           
        }
                 
    }
protected override DriverResult Editor(BeltsPart part, Orchard.ContentManagement.IUpdateModel updater, dynamic shapeHelper)
        {
            var model = new EditBeltsViewModel();
            updater.TryUpdateModel(model, Prefix, null, null);

            if (part.ContentItem.Id != 0)
            {
                _martialArtService.UpdateBeltsForContentItem(part.ContentItem, model.Belts);
            }

            return Editor(part, shapeHelper);
        }
public class BeltsRecord:ContentPartRecord
    {
        public BeltsRecord()
        {
            Belts = new List();
        }
        public virtual IList Belts { get; set; }
    }
public class ContentBeltProgramsRecord:ContentPartRecord
    {
        public virtual BeltsRecord BeltsRecord { get; set; }
        public virtual BeltRecord BeltRecord { get; set; }
    }
public class EditBeltsViewModel
    {
        public IList Belts { get; set; }
    }

    public class BeltProgramEntry{
        public BeltRecord Belt { get; set; }
        public bool IsChecked { get; set; }
    }

Coordinator
Feb 17, 2011 at 4:08 AM

Do you still have a question?

Feb 17, 2011 at 11:41 AM

yes, the question is above. i am not understanding why i am receiving this error and to get a better understanging of n to n rlationships.

Feb 17, 2011 at 2:26 PM

Sorry, I meant in my reply that before I created this discussion, I already fixed the migration errors.

I am noticing that I am getting multiple entries into my Routable_RoutePartRecord when I save the Program (ContentItem).

protected override DriverResult Editor(ProgramPart part, IUpdateModel updater, dynamic shapeHelper)
        {
            var model = new EditProgramViewModel();
            updater.TryUpdateModel(model, Prefix, null, null);
            if (part.ContentItem.Id != 0)
            {
                _martialArtService.UpdateProgramForContentItem(part.ContentItem, model);
            }
            return Editor(part, shapeHelper);
        }

public void UpdateProgramForContentItem(ContentItem item, ViewModels.EditProgramViewModel model)
        {
            var programPart = item.As();
            programPart.MaximumAge = model.MaximumAge;
            programPart.MinimumAge = model.MinimumAge;
            programPart.Active = model.Active;
            programPart.MartialArtRecord = _martialArtRepository.Get(
                s => s.Id == model.MartialArtId
                );
        }
 public int Create() {
			// Creating table MartialArtRecord
			SchemaBuilder.CreateTable("MartialArtRecord", table => table
				.ContentPartRecord()
				.Column("Active", DbType.Boolean)
				.Column("Name", DbType.String)
			);

			// Creating table ProgramRecord
			SchemaBuilder.CreateTable("ProgramRecord", table => table
				.ContentPartRecord()
				.Column("MinimumAge", DbType.Int32)
				.Column("MaximumAge", DbType.Int32)
				.Column("Active", DbType.Boolean)
                .Column("MartialArtRecord_id", DbType.Int32)
			);

            SchemaBuilder.CreateTable("BeltRecord", table => table
                .ContentPartRecord()
                .Column("Name", DbType.String)
            );
            
            SchemaBuilder.CreateTable("BeltsRecord", table => table
                .ContentPartRecord()
            );

            SchemaBuilder.CreateTable("ContentBeltProgramsRecord", table => table
                .ContentPartRecord()
                .Column("Belt_id", DbType.Int32)
                .Column("Belts_id", DbType.Int32)
            );

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

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

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

            ContentDefinitionManager.AlterTypeDefinition("MartialArt", cfg => cfg
                .WithPart(typeof(CommonPart).Name)
                .WithPart(typeof(BodyPart).Name)
                .WithPart(typeof(ContainablePart).Name)
                .WithPart(typeof(RoutePart).Name)
                .WithPart(typeof(MartialArtPart).Name)
                .Creatable());

            ContentDefinitionManager.AlterTypeDefinition("Program", cfg => cfg
                .WithPart(typeof(CommonPart).Name)
                .WithPart(typeof(ContainablePart).Name)
                .WithPart(typeof(RoutePart).Name)
                .WithPart(typeof(ProgramPart).Name)
                .WithPart(typeof(BodyPart).Name)
                .WithPart(typeof(BeltsPart).Name)
                .Creatable());            

            ContentDefinitionManager.AlterTypeDefinition("Belt", cfg => cfg
                .WithPart(typeof(CommonPart).Name)
                .WithPart(typeof(BeltPart).Name)
                .Creatable());

            //ContentDefinitionManager.AlterTypeDefinition("User",
            //    cfg => cfg
            //        .WithPart(typeof(ProgramPart).Name)
            //    );
            return 1;
        }

Coordinator
Feb 17, 2011 at 7:39 PM

Did you zap the database and restart from scratch after you fixed the migration? One thing that I notice in your migration is that the column names for the relations don't seem to correspond to the property names on the records. The correspondence is convention-based so you need to scrupulously use the same names for the columns (plus _id) and properties.

Mar 24, 2011 at 4:27 PM

I'm not sure if this is the problem here, but I got the same error message when I was trying to save a record that was part of a 1-n relationship, but wasn't associated with a content part.

The problem was that my record inheritted from ContentPartRecord (which was wrong because in my case it was not associated with a content part).

I removed : ContentPartRecord from my model class and added an Id property. Then all was well.

I hope this helps, or at least helps someone googling for the same error message.