我正在使用该指南在Orchard(ocs.orchardproject.net/Documentation/Creating-1-n-and-n-n-relations)中创建n-to-n关系,稍作修改。虽然示例代码运行良好,但在创建或编辑项目后,我自己的内容部分始终为空白。我无法理解,因为我发誓我的代码几乎与他们的代码相同(除了内容部分有更多/更少的无关字段)。
我怀疑它可能与驱动程序中的前缀有关。我真的不知道前缀应该做什么,但是将其设置为一个值会在创建/编辑时产生运行时错误,其他值只会产生所有字段为空的结果。
原始样本工作正常,所以它必须是我做过或不做过的事情,但我无法弄清楚它是什么。
一些相关课程:
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));
}
}
}
答案 0 :(得分:2)
您的StreetAreaRecord模型缺少Id属性。由于它不是ContentPartRecord,您必须手动设置属性。
public virtual int Id { get; set; }
答案 1 :(得分:0)
前缀用于确保零件编辑器中html字段中的唯一id属性。您可能在单个内容类型中有多个部分,并带有“名称”字段。没有前缀,html将无效,并且回发将无法工作,因为将有两个id =“Name”的字段。您只需将前缀设置为零件的名称即可。
我不确定前缀是什么阻止你的部分保存。您是否检查过Handler?确保它为StreetPartRecord设置过滤器,这通常是新部件无法在回发时保存的原因。