No persister for: PersonModule.PersonRecord

Topics: Troubleshooting, Writing modules
Aug 5, 2011 at 9:43 PM

I am trying to write a simple module and when i am creating a Person type , i am getting No persister for exception while saving edit form. 

Why i am getting this problem ? How can i fix it ?

 

namespace PersonModule
{
    public class PersonRecord : ContentPartRecord
    {
        public virtual string Name { get; set; }
        public virtual int Age { get; set; }
    }

    public class PersonPart : ContentPart<PersonRecord>
    {
        public string Name
        {
            get { return Record.Name; }
            set { Record.Name = value; }
        }

        public int Age
        {
            get { return Record.Age; }
            set { Record.Age = value; }
        }

    }

    public class PersonPartDriver : ContentPartDriver<PersonPart>
    {
        protected override DriverResult Display(PersonPart part, string displayType, dynamic shapeHelper)
        {
            return this.ContentShape("Parts_Person", () => shapeHelper.Part_Person(
                Name: part.Name,
                Age: part.Age
                ));
        }

        protected override DriverResult Editor(PersonPart part, dynamic shapeHelper)
        {
            return ContentShape("Parts_Person_Edit", () => shapeHelper.EditorTemplate(
                Model: part,
                Prefix: Prefix,
                TemplateName: "Parts/Person"
                ));
        }

        protected override DriverResult Editor(PersonPart part, IUpdateModel updater, dynamic shapeHelper)
        {
            updater.TryUpdateModel(part, Prefix, null, null);
            return Editor(part, shapeHelper);
        }
    }

    public class PersonHandler : ContentHandler
    {
        public PersonHandler(IRepository<PersonRecord> repository)
        {
            Filters.Add(StorageFilter.For(repository));
        }

    }

    public class Migration : DataMigrationImpl
    {
        public int Create()
        {
            SchemaBuilder.CreateTable(typeof(PersonRecord).Name, c => c.Column<string>("Name").Column<int>("Age").ContentPartRecord());
            ContentDefinitionManager.AlterPartDefinition(typeof(PersonPart).Name, cfg => cfg.Attachable());
            ContentDefinitionManager.AlterTypeDefinition("PersonType", cfg => cfg.WithPart("PersonPart").Creatable());
            return 1;
        }
    }
}

Aug 6, 2011 at 6:59 PM
Edited Aug 6, 2011 at 7:00 PM

Is there anyone who has an idea about it ? Is there any problem on code that i am write ?

Coordinator
Aug 6, 2011 at 7:21 PM
I have a similar bug in one of my modules. Haven't found the cause yet. I'll keep you posted.

Sent from my TI-99/4A

From: YakupIpek
Sent: Saturday, August 06, 2011 11:00 AM
To: Bertrand Le Roy
Subject: Re: No persister for: PersonModule.PersonRecord [orchard:267968]

From: YakupIpek

Is there anyone who has an idea about it ?

Aug 6, 2011 at 9:16 PM
Edited Aug 6, 2011 at 9:17 PM

My project name was "SamplePersonModule"  but i used "PersonModule" as namespace in my sample. I just tried to change namespace to my project name and it worked huhhh ?

 

How namespace has strong relation with project name for Orchard ?

Coordinator
Aug 6, 2011 at 9:33 PM
Interesting, weird and buggy. Thanks I'll investigate that.

Sent from my TI-99/4A

From: YakupIpek
Sent: Saturday, August 06, 2011 1:16 PM
To: Bertrand Le Roy
Subject: Re: No persister for: PersonModule.PersonRecord [orchard:267968]

From: YakupIpek

My project name was "SamplePersonModule" but i used "PersonModule" as namespace in my sample. I just tried to change namespace to my project name and it worked huhhh ? How namespace has strong relation with project name for Orchard ?

Nov 28, 2012 at 11:29 AM

We ran into a very similar issue today that cost us quite some time to investigate and fix. Running Orchard 1.3 still.

Thanks to YakupIpek for the hint with the namespace synchronisation problem - in our case we had the Part and (especially) the PartRecord files defined in a folder other than Models which led to NHibernate not creating/finding the mapping for that Record!

The fix is to simply stuff them into the Models folder of your module.

WHY?

Because Orchard.Environment.ShellBuilders.CompositionStrategy contains the following IsRecord() method:

private static bool IsRecord(Type type) {
    return ((type.Namespace ?? "").EndsWith(".Models") || (type.Namespace ?? "").EndsWith(".Records")) &&
            type.GetProperty("Id") != null &&
            (type.GetProperty("Id").GetAccessors() ?? Enumerable.Empty<MethodInfo>()).All(x => x.IsVirtual) &&
            !type.IsSealed &&
            !type.IsAbstract &&
            (!typeof(IContent).IsAssignableFrom(type) || typeof(ContentPartRecord).IsAssignableFrom(type));
}

Is it really sensible to restrict the namespaces of Records to end with "Models" or "Records"? This seems like an unnecessary restriction to me, especially since the last check is for inheritance from ContentPartRecord...

Coordinator
Nov 28, 2012 at 10:58 PM
Edited Nov 28, 2012 at 11:00 PM

Yes. It's a convention. Records don't necessarily derive from ContentPartRecord (notice the ||s).