IContentHandler order in InvokeExtension.cs

Topics: Customizing Orchard, Troubleshooting, Writing modules
Oct 5, 2013 at 6:07 PM
Heya all,

I'm encountering another problem, which I don't know how to fix.

My Problem is, that I've a dependency between my Parts attached to my ContentType, which means that I need the handler (driver etc.) to be called in the correct order, otherwise my creation process won't be successful.

I've figured out, that the handlers are given to InvokeExtension.cs , which just iterates over all handles and triggers them. Is there a way to edit the order of the Handlers given to this class? My problem is, that my handles are in the wrong order, within the events var in InvokeExtension.

Do you know a way?

Thanks,
SantoDE
Coordinator
Oct 5, 2013 at 9:55 PM
Parts should never depend on one another. What's the scenario?
Oct 5, 2013 at 10:10 PM
I have a content type, which I assign various parts. Let's say I've ContentPartA and ContentPartB.

ContentPartA and B are a ListParts, which store various Records (1 - N relation).

ContentPartB now has a reference to a record, stored in the ListPart of ContentPartA therefore I need to ensure that A becomes created first.

Hope this was clear.
Coordinator
Oct 6, 2013 at 4:46 AM
Not really. In any case, parts should be designed to be independent of one another and to be able to stand on their own. If your lists are going to be coupled, then maybe they should be on the same part?
Oct 7, 2013 at 12:53 PM
BertrandLeRoy wrote:
Not really. In any case, parts should be designed to be independent of one another and to be able to stand on their own. If your lists are going to be coupled, then maybe they should be on the same part?
That's what I tried as well, but I can't get it to work either.

When I add another lazy loaded list to the part, give the second repository to my service and try to store a record, the only error I receive is :
No persister for: Orchard.Projekt.Models.CupPairingRecord
Is there any trick I need todo to store 2 different "normal" records within a part?
Coordinator
Oct 7, 2013 at 4:21 PM
Hard to say with so little information, but it seems like you have a naming issue here, preventing the mapping from working.
Oct 7, 2013 at 6:03 PM
Edited Oct 7, 2013 at 6:25 PM
Looks like you're right. I can't see this class within my mappings, either.

Here are my model files:
namespace Orchard.Projekt.Models
{
    public class CupStructurePart : ContentPart<CupStructurePartRecord>
    {
        private readonly LazyField<IEnumerable<CupRoundRecord>> _cupRounds = new LazyField<IEnumerable<CupRoundRecord>>();
        private readonly LazyField<IEnumerable<CupMatchesRecord>> _cupPairings = new LazyField<IEnumerable<CupMatchesRecord>>();

        public CupRecord CupRecord
        {
            get { return Record.CupRecord; }
            set { Record.CupRecord = value; }
        }

        [Required]
        public int MaxCount
        {
            get { return Record.MaxCount; }
            set { Record.MaxCount = value; }
        }

        public LazyField<IEnumerable<CupRoundRecord>> CupRoundsField
        {
            get { return _cupRounds; }
        }

        public IEnumerable<CupRoundRecord> CupRounds
        {
            get { return _cupRounds.Value; }
        }

        public LazyField<IEnumerable<CupMatchesRecord>> CupPairingsField
        {
            get { return _cupPairings; }
        }

        public IEnumerable<CupMatchesRecord> CupPairings
        {
            get { return _cupPairings.Value; }
        }
    }
    
    public class CupStructurePartRecord : ContentPartRecord
    {
        public virtual CupRecord CupRecord { get; set; }
        public virtual int MaxCount { get; set; }

        public CupStructurePartRecord()
        {
            MaxCount = 10;
        }
    }
}
namespace Orchard.Projekt.Models
{
    public class CupMatchesRecord
    {
        public virtual CupRoundRecord CupRoundRecord { get; set; }
        public virtual CupMatchesRecord NextCupMatchesRecord{ get; set; }
        public virtual CupContestantRecord UpperCupContestantRecord { get; set; }
        public virtual CupContestantRecord LowerCupContestantRecord { get; set; }
        public virtual CupContestantRecord WinnerCupContestantRecord { get; set; }
        public virtual int UpperSeeding { get; set; }
        public virtual int LowerSeeding { get; set; }
    }
}
namespace Orchard.Projekt.Models
{
    public class CupRoundRecord
    {
        public virtual int Id { get; set; }
        public virtual int Number { get; set; }
        public virtual CupRecord CupRecord { get; set; }
    }
}
It works for the CupRoundRecord, but not for the matches one :/
Coordinator
Oct 7, 2013 at 6:13 PM
The problem may be in your migration.
Oct 7, 2013 at 6:27 PM
Ok, in this case:
namespace Orchard.Projekt {
    public class Migrations : DataMigrationImpl {

        public int Create() {
            // Creating table Cups
            SchemaBuilder.CreateTable("CupRecord", table => table
                .ContentPartRecord()
                .Column<string>("Name")
                .Column<string>("Server")
                .Column<int>("Size")
                .Column<DateTime>("StartDate")
                .Column<DateTime>("SignUpFrom")
                .Column<DateTime>("SignUpTo")
                .Column<int>("Active")
            );

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

            // Creating table CupRoundListPart
            SchemaBuilder.CreateTable("CupStructurePartRecord", table => table
                .ContentPartRecord()
                .Column<int>("CupRecord_Id")
                .Column<int>("MaxCount")
            );

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

            // Creating table CupRound
            SchemaBuilder.CreateTable("CupRoundRecord", table => table
                .Column<int>("Id", column => column.PrimaryKey().Identity())
                .Column<int>("Number")
                .Column<int>("CupRecord_Id")
            );

            // Creating table CupPairing
            SchemaBuilder.CreateTable("CupMatchesRecord", table => table
                .ContentPartRecord()
                .Column("CupRoundRecord_id", DbType.Int32)
                .Column("NextCupMatchesRecord_Id", DbType.Int32)
                .Column("UpperCupContestantRecord_Id", DbType.Int32)
                .Column("LowerCupContestantRecord_Id", DbType.Int32)
                .Column("WinnerCupContestantRecord_Id", DbType.Int32)
                .Column("UpperSeeding", DbType.Int32)
                .Column("LowerSeeding", DbType.Int32)

            );

            // Creating table CupContestant
            SchemaBuilder.CreateTable("CupContestantListPartRecord", table => table
                .ContentPartRecord()
                .Column<int>("CupRecord_Id")
                .Column<int>("MaxCount")
            );

            // Creating table CupContestant
            SchemaBuilder.CreateTable("CupContestantRecord", table => table
                .ContentPartRecord()
                .Column("CharName", DbType.String)
                .Column("AccountName", DbType.String)
                .Column("Cup_Id", DbType.Int32)
                .Column("Seeding", DbType.Int32)
                .Column("SignUpDate", DbType.DateTime)
            );

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

            return 1;
        }
    }
}
Thanks for your help!
Coordinator
Oct 7, 2013 at 7:14 PM
Ah, no, I think it's just that your matches record class doesn't have an id.
Oct 8, 2013 at 3:23 PM
You were absolutely right. Thanks :)

Now, I've another question:

I made it to work, which means I can now generate both records within this "single Part".

However, I guess I'm encountering another order issue:

As far as I understand Orchard / NHibernate, it just sets a transaction for the whole "creation of a part process", which means that the transaction is not commited until the whole part (and therefore all of my single records) are created.

Sadly, I've to set a reference from one db entry to another which is rather hard to achieve as I can't select the item out of the database as it's not stored there yet, due to the transaction not being committed at this point.

I tried to solve this problem by using different Orchard lifecycle events (OnXXX), but this doesn't seem to solve my problem either.

Is there any other good way?

Thanks.
Coordinator
Oct 9, 2013 at 6:20 AM
Shouldn't matter: you should be setting references to objects, which you have. Then nHibernate will know how to map those to ids.
Oct 9, 2013 at 10:40 AM
Yap, I've fixed it :D Thanks :)