2

Orchard で n 対 n の関係を作成するためのガイド (ocs.orchardproject.net/Documentation/Creating-1-n-and-nn-relations) を少し変更して使用しています。サンプル コードは問題なく機能しますが、アイテムを作成または編集した後、自分のコンテンツ パーツは常に空白です。私のコードが彼らのコードとほぼ同じであることを誓うので、それを理解することはできません(コンテンツ部分には無関係なフィールドが多かれ少なかれ含まれていることを除いて)。

ドライバーのプレフィックスと関係があるのではないかと思います。プレフィックスが何をすべきかはよくわかりませんが、1 つの値に設定すると作成/編集時に実行時エラーが発生し、他の値ではすべてのフィールドが空白の結果が生成されます。

元のサンプルは問題なく動作するので、それは私が行った、または行っていないものである必要がありますが、それが何であるかを理解することはできません.

関連するクラス:

using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using ArealAds.Models;
using ArealAds.Services;
using ArealAds.ViewModels;

namespace ArealAds.Drivers {
    [UsedImplicitly]
    public class StreetPartDriver : ContentPartDriver<StreetPart> {
        private readonly IStreetService _streetService;

        private const string TemplateName = "Parts/Street";

        public StreetPartDriver(IStreetService streetService) {
            _streetService = streetService;
        }

        // this one gives a runtime error with blank description,
        // other values produce result with all fields blank
        protected override string Prefix {
            get { return "Area"; }
        }

        protected override DriverResult Display(StreetPart part, string displayType, dynamic shapeHelper) {
            return ContentShape("Parts_Street",
                            () => shapeHelper.Parts_Street(
                                ContentPart: part,
                                Name: part.Name,
                                Areas: part.Areas,
                                Districts: part.Districts));

        }

        protected override DriverResult Editor(StreetPart part, dynamic shapeHelper) {
            return ContentShape("Parts_Street_Edit",
                    () => shapeHelper.EditorTemplate(
                        TemplateName: TemplateName,
                        Model: BuildEditorViewModel(part),
                        Prefix: Prefix));
        }

        protected override DriverResult Editor(StreetPart part, IUpdateModel updater, dynamic shapeHelper) {
            var model = new EditStreetViewModel();
            updater.TryUpdateModel(model, Prefix, null, null);

            if (part.ContentItem.Id != 0) {
                _streetService.UpdateAreasForContentItem(part.ContentItem, model.Areas);
            }

            return Editor(part, shapeHelper);
        }

        private EditStreetViewModel BuildEditorViewModel(StreetPart part) {
            var itemAreas = part.Areas.ToLookup(r => r.Id);
            return new EditStreetViewModel {
                Areas = _streetService.GetAreas().Select(r => new AreaEntry {
                    Area = r,
                    IsChecked = itemAreas.Contains(r.Id)
                }).ToList()
            };
        }
    }
}


using System.Collections.Generic;
using System.Linq;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Data;
using ArealAds.Models;
using ArealAds.ViewModels;

namespace ArealAds.Services {
    public interface IStreetService : IDependency {
        void UpdateAreasForContentItem(ContentItem item, IEnumerable<AreaEntry> areas);
        IEnumerable<AreaRecord> GetAreas();
    }

    public class StreetService : IStreetService {
        private readonly IRepository<AreaRecord> _areaRepository;
        private readonly IRepository<StreetAreaRecord> _streetAreaRepository;

        public StreetService(
            IRepository<AreaRecord> areaRepository,
            IRepository<StreetAreaRecord> streetAreaRepository) {

            _areaRepository = areaRepository;
            _streetAreaRepository = streetAreaRepository;
        }

        public void UpdateAreasForContentItem(ContentItem item, IEnumerable<AreaEntry> areas) {
            var record = item.As<StreetPart>().Record;
            var oldAreas = _streetAreaRepository.Fetch(
                r => r.StreetRecord == record);
            var lookupNew = areas
                .Where(e => e.IsChecked)
                .Select(e => e.Area)
                .ToDictionary(r => r, r => false);
            // Delete the areas that are no longer there and mark the ones that should stay
            foreach(var streetAreaRecord in oldAreas) {
                if (lookupNew.ContainsKey(streetAreaRecord.AreaRecord)) {
                    lookupNew[streetAreaRecord.AreaRecord] = true;
                }
                else {
                    _streetAreaRepository.Delete(streetAreaRecord);
                }
            }
            // Add the new areas
            foreach(var area in lookupNew.Where(kvp => !kvp.Value).Select(kvp => kvp.Key)) {
                _streetAreaRepository.Create(new StreetAreaRecord {
                    StreetRecord = record,
                    AreaRecord = area
                });
            }
        }

        public IEnumerable<AreaRecord> GetAreas() {
            return _areaRepository.Table.ToList();
        }
    }
}


using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;

namespace ArealAds.Models {
    public class StreetAreaRecord : ContentPartRecord {
        public virtual StreetRecord StreetRecord { get; set; }
        public virtual AreaRecord AreaRecord { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Data;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;
using ArealAds.Models;

namespace ArealAds {
    public class Migrations : DataMigrationImpl {

        public int Create() {
            //
            // Street-Area-District
            //

            SchemaBuilder.CreateTable("DistrictRecord", table => table
                .ContentPartRecord()
                .Column<string>("Name")
            );

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

            ContentDefinitionManager.AlterTypeDefinition(
                "District", cfg => cfg
                .WithPart("CommonPart")
                .WithPart("DistrictPart")
                .Creatable()
            );

            SchemaBuilder.CreateTable("AreaRecord", table => table
                .ContentPartRecord()
                .Column<string>("Name")
                .Column<int>("DistrictRecord_Id")
            );

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

            ContentDefinitionManager.AlterTypeDefinition(
                "Area", cfg => cfg
                .WithPart("CommonPart")
                .WithPart("AreaPart")
                .Creatable()
            );

            SchemaBuilder.CreateTable("StreetRecord", table => table
                .ContentPartRecord()
                .Column<string>("Name")
            );

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

            ContentDefinitionManager.AlterTypeDefinition(
                "Street", cfg => cfg
                .WithPart("CommonPart")
                .WithPart("StreetPart")
                .Creatable()
            );

            SchemaBuilder.CreateTable("StreetAreaRecord", table => table
                .Column<int>("Id", column => column.PrimaryKey().Identity())
                .Column<int>("StreetRecord_Id")
                .Column<int>("AreaRecord_Id")
            );


            //
            // Address-Ad
            //

            SchemaBuilder.CreateTable("AddressRecord", table => table
                .ContentPartRecord()
                .Column<int>("StreetRecord_Id")
                .Column<int>("Building")
                .Column<int>("Kor")
                .Column<int>("Str")
                .Column<int>("Vl")
                .Column<string>("Note")
                .Column<int>("AreaRecord_Id")
                .Column<int>("DistrictRecord_Id")
                .Column<string>("Phone1")
                .Column<string>("Phone2")
                .Column<string>("Phone3")
            );

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


            return 1;
        }
    }
}

@model ArealAds.ViewModels.EditStreetViewModel
<fieldset>
    <legend>Улица</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Street.Name)
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(model => model.Street.Name)
        @Html.ValidationMessageFor(model => model.Street.Name)
    </div>
<ul>

@for (int i = 0; i < Model.Areas.Count; i++) {
    <li>
        <input type="hidden" value="@Model.Areas[i].Area.Id"
               name="@Html.FieldNameFor(m => m.Areas[i].Area.Id)"/>

        <label for="@Html.FieldNameFor(m => m.Areas[i].IsChecked)">

            <input type="checkbox" value="true"
                name="@Html.FieldNameFor(m => m.Areas[i].IsChecked)"
                id="@Html.FieldNameFor(m => m.Areas[i].IsChecked)"
                @if (Model.Areas[i].IsChecked) {<text>checked="checked"</text>}/>

            @Model.Areas[i].Area.Name
        </label>
    </li>
}
</ul>
</fieldset>

私はこれについて何日も壁に頭をぶつけていました。理論的に役立つと思われる提案をしてください。私は必死です:(

UPD: StreetHandler クラス:

using ArealAds.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;

namespace ArealAds.Handlers {
    public class StreetHandler : ContentHandler {
        public StreetHandler(IRepository<StreetRecord> repository) {
            Filters.Add(StorageFilter.For(repository));
        }
    }
}

ログに例外があります:

2012-04-10 00:07:58,515 [7] Orchard.ContentManagement.Drivers.Coordinators.ContentPartDriverCoordinator - IdentifierGenerationException thrown from IContentPartDriver by ArealAds.Drivers.StreetPartDriver
NHibernate.Id.IdentifierGenerationException: attempted to assign id from null one-to-one property: ContentItemRecord
   â NHibernate.Id.ForeignGenerator.Generate(ISessionImplementor sessionImplementor, Object obj)
   â NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
   â NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
   â NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
   â NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
   â NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
   â NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
   â NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
   â NHibernate.Impl.SessionImpl.Save(Object obj)
   â Orchard.Data.Repository`1.Create(T entity) â d:\TeamCity\Projects\Orchard-Default\src\Orchard\Data\Repository.cs:ñòðîêà 96
   â Orchard.Data.Repository`1.Orchard.Data.IRepository<T>.Create(T entity) â d:\TeamCity\Projects\Orchard-Default\src\Orchard\Data\Repository.cs:ñòðîêà 36
   â ArealAds.Services.StreetService.UpdateAreasForContentItem(ContentItem item, IEnumerable`1 areas) â c:\Users\Mom\Teritoriya\Modules\ArealAds\Services\Street.cs:ñòðîêà 46
   â ArealAds.Drivers.StreetPartDriver.Editor(StreetPart part, IUpdateModel updater, Object shapeHelper) â c:\Users\Mom\Teritoriya\Modules\ArealAds\Controllers\Street.cs:ñòðîêà 47
   â System.Dynamic.UpdateDelegates.UpdateAndExecute4[T0,T1,T2,T3,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3)
   â Orchard.ContentManagement.Drivers.ContentPartDriver`1.Orchard.ContentManagement.Drivers.IContentPartDriver.UpdateEditor(UpdateEditorContext context) â d:\TeamCity\Projects\Orchard-Default\src\Orchard\ContentManagement\Drivers\ContentPartDriver.cs:ñòðîêà 30
   â Orchard.ContentManagement.Drivers.Coordinators.ContentPartDriverCoordinator.<>c__DisplayClass10.<UpdateEditor>b__f(IContentPartDriver driver) â d:\TeamCity\Projects\Orchard-Default\src\Orchard\ContentManagement\Drivers\Coordinators\ContentPartDriverCoordinator.cs:ñòðîêà 61
   â Orchard.InvokeExtensions.Invoke[TEvents](IEnumerable`1 events, Action`1 dispatch, ILogger logger) â d:\TeamCity\Projects\Orchard-Default\src\Orchard\InvokeExtensions.cs:ñòðîêà 19

編集: いくつかのモデル クラス:

using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;

namespace ArealAds.Models {
    public class AreaRecord : ContentPartRecord {
        public virtual string Name { get; set; }
        public virtual DistrictRecord DistrictRecord { get; set; }
    }

    public class AreaPart : ContentPart<AreaRecord> {
        [Required]
        public string Name {
            get { return Record.Name; }
            set { Record.Name = value; }
        }

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

using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;

namespace ArealAds.Models {
    public class StreetRecord : ContentPartRecord {
        public virtual string Name { get; set; }
        public virtual IList<StreetAreaRecord> Areas { get; set; }

        public StreetRecord() {
            Areas = new List<StreetAreaRecord>();
        }
    }

    public class StreetPart : ContentPart<StreetRecord> {
        [Required]
        public string Name {
            get { return Record.Name; }
            set { Record.Name = value; }
        }

        public IEnumerable<AreaRecord> Areas {
            get {
                return Record.Areas.Select (r => r.AreaRecord);
            }
        }

        public IEnumerable<DistrictRecord> Districts {
            get {
                return Record.Areas.Select (r => r.AreaRecord.DistrictRecord).Distinct();
            }
        }
    }
}

using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;

namespace ArealAds.Models {
    public class StreetAreaRecord : ContentPartRecord {
        public virtual StreetRecord StreetRecord { get; set; }
        public virtual AreaRecord AreaRecord { get; set; }
    }
}

using ArealAds.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;

namespace ArealAds.Handlers {
    public class AreaHandler : ContentHandler {
        public AreaHandler(IRepository<AreaRecord> repository) {
            Filters.Add(StorageFilter.For(repository));
        }
    }
}

using ArealAds.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;

namespace ArealAds.Handlers {
    public class StreetHandler : ContentHandler {
        public StreetHandler(IRepository<StreetRecord> repository) {
            Filters.Add(StorageFilter.For(repository));
        }
    }
}
4

2 に答える 2

2

StreetAreaRecord モデルに Id プロパティがありません。これは ContentPartRecord ではないため、プロパティを手動で設定する必要があります。

public virtual int Id { get; set; }
于 2012-04-10T02:59:06.907 に答える
0

プレフィックスは、パーツエディタのhtmlフィールドで一意のid属性を確保するためのものです。「名前」フィールドを持つ単一のコンテンツタイプ内に複数の部分がある場合があります。プレフィックスがないと、htmlは無効になり、id = "Name"のフィールドが2つあるため、ポストバックは機能しません。プレフィックスをパーツの名前に設定するだけです。

プレフィックスがあなたのパーツの保存を妨げているのかわかりません。あなたはあなたの部分のハンドラーをチェックしましたか?StreetPartRecordのフィルターが設定されていることを確認してください。これは、多くの場合、新しいパーツがポストバックで保存されない原因です。

于 2012-04-09T13:54:08.503 に答える