博客文章

Orchard下的Master-Detail操作

作者: zxtko      时间: 2014年5月21日 11:10:00

Orchard官方文档有1-N关系的列子,主体思想是建立一个EditView Model,将N的数据传递到View上。它也有缺点:这个Model,和View是不能重用的,在繁琐的Web开发中,增加了负担。

我打算利用一个List Part来处理这种关系,主要是想重复利用这个List Part,View,Model都能重用。 举例,Enterprise - Factory,是1对多的关系。我想在 Edit Enterprise View下,删除Factory。

建立 EnterprisePart, FactoryPart, FactoryListPart。 FactoryPaort Attach到EnterprisePart上。两个Driver,EnterpriseDriver,FactoryListDriver。这里有个问题,两个Driver是独立的,FactoryList无法获取Enterprise,怎么解决?在Handler中解决!

            OnLoaded((c, t) => { _orchardServices.WorkContext.SetState("Enterprise", t.Record); }); 

OK,在Load Enterprise的时候我们把它存在 WorkContext中(类似Request.Items)。在FactoryListPartDriver中,我们就能获取到Enterprise啦!
我们可以将 FactoryListPart Attach到别的Part上,一定程度的复用。看代码吧:

//Records & Parts
    public class EnterpriseRecord : ContentPartRecord
    {
        public virtual string Name { get; set; }
    }

    public class FactoryRecord : ContentPartRecord
    {
        public virtual string Name { get; set; }
        public virtual EnterpriseRecord Enterprise { get; set; }
    }

    public class EnterprisePart : ContentPart { [Required] public string Name { get { return Record.Name; } set { Record.Name = value; } } } public class FactoryPart : ContentPart { [Required] public string Name { get { return Record.Name; } set { Record.Name = value; } } public EnterpriseRecord Enterprise { get { return Record.Enterprise; } set { Record.Enterprise = value; } } } public class FactoryListPart : ContentPart { private readonly LazyField<IEnumerable> _factories = new LazyField<IEnumerable>(); public LazyField<IEnumerable> FactoriesFeild { get { return _factories; } } public IEnumerable Factories { get { return _factories.Value; } } } // Drivers public class EnterpriseDriver : ContentPartDriver { protected override DriverResult Display( EnterprisePart part, string displayType, dynamic shapeHelper) { return ContentShape("Parts_Enterprise", () => shapeHelper.Parts_Enterprise( Name: part.Name)); } //GET protected override DriverResult Editor(EnterprisePart part, dynamic shapeHelper) { return ContentShape("Parts_Enterprise_Edit", () => shapeHelper.EditorTemplate( TemplateName: "Parts/Enterprise", Model: part, Prefix: Prefix)); } //POST protected override DriverResult Editor(EnterprisePart part, IUpdateModel updater, dynamic shapeHelper) { updater.TryUpdateModel(part, Prefix, null, null); return Editor(part, shapeHelper); } } public class FactoryListDriver : ContentPartDriver { private readonly IOrchardServices _orchardServices; private readonly IEnterpriseService _enterpriseService; public FactoryListDriver(IOrchardServices orchardServices, IEnterpriseService enterpriseService) { _orchardServices = orchardServices; _enterpriseService = enterpriseService; } protected override DriverResult Display(FactoryListPart part, string displayType, dynamic shapeHelper) { return ContentShape("Parts_FactoryList", () => shapeHelper.Parts_FactoryList( Name: "FactoryList")); } //GET protected override DriverResult Editor(FactoryListPart part, dynamic shapeHelper) { var enterprise = _orchardServices.WorkContext.GetState("Enterprise"); part.FactoriesFeild.Loader(delegate { return _enterpriseService.GetFactories(enterprise); }); return ContentShape("Parts_FactoryList_Edit", () => shapeHelper.EditorTemplate( TemplateName: "Parts/FactoryList", Model: part, Prefix: Prefix)); } //POST protected override DriverResult Editor(FactoryListPart part, IUpdateModel updater, dynamic shapeHelper) { return Editor(part, shapeHelper); } } //handler Filters.Add(StorageFilter.For(enterpriseRepository)); Filters.Add(StorageFilter.For(factoryRepository)); OnLoaded((c, t) => { _orchardServices.WorkContext.SetState("Enterprise", t.Record); }); //Migrations ContentDefinitionManager.AlterPartDefinition("EnterprisePart", builder => builder.Attachable()); ContentDefinitionManager.AlterPartDefinition("FactoryPart", builder => builder.Attachable()); ContentDefinitionManager.AlterPartDefinition("FactoryListPart", builder => builder.Attachable(false)); ContentDefinitionManager.AlterTypeDefinition("Enterprise", cfg => cfg .WithPart("EnterprisePart") .WithPart("CommonPart") .WithPart("FactoryListPart") .Creatable()); //Don't forget placement.info