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));
}
}
}