Jul 18, 2012 at 11:43 AM
Edited Jul 18, 2012 at 11:46 AM
|
I have a workaround which appears to work with my model (a container part that has a collection of related records) but I'm not sure if it'll work with the examples in the Orchard 1-n and n-n documentation. The problem was as I suspected - the Orchard versioning
code uses NHibernate to copy each part when creating a new draft, including related records.
My model:
public class MyPartRecordWithCollection : ContentPartVersionRecord
{
public MyPartRecordWithCollection()
{
this.Collection = new List<MyCollectionItem>();
}
public virtual IList<MyCollectionItem> Collection { get; set; }
}
public class MyCollectionItem
{
public virtual int Id { get; set; }
// some other properties
public virtual MyPartRecordWithCollection MyPartRecordWithCollection { get; set; }
}
Migration:
this.SchemaBuilder.CreateTable("MyCollectionItem", table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<int>("MyPartRecordWithCollection_id"));
this.SchemaBuilder.CreateTable("MyPartRecordWithCollection", table => table.ContentPartVersionRecord());
I've found I can modify ContentHandler to use a custom storage filter rather than calling StorageFilter.For, and change the way the new version is created, as the storage filter that's assigned by default is what's causing the problem...
Filters.Add(new MyStorageVersionFilter(repository))
Here is the code for the filter:
public class MyStorageVersionFilter : StorageVersionFilter<MyPartRecordWithCollection>
{
public MyStorageVersionFilter(
IRepository<MyPartRecordWithCollection> repository)
: base(repository)
{
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
protected override void Versioning(VersionContentContext context, ContentPart<MyPartRecordWithCollection> existing, ContentPart<MyPartRecordWithCollection> building)
{
// overriding the base copy logic to create new references rather than copying the existing ones
CopyRecord(existing, building);
// only the up-reference to the particular version differs at this point
building.Record.ContentItemVersionRecord = context.BuildingItemVersionRecord;
// push the new instance into the transaction and session
_repository.Create(building.Record);
}
private void CopyRecord(ContentPart<MyPartRecordWithCollection> existing, ContentPart<MyPartRecordWithCollection> building)
{
Logger.Debug("Copy {0} {1}", existing, building);
foreach (var existingCollectionItem in existing.Record.Collection)
{
var newCollectionItem = new MyCollectionItem();
// Use existingCollectionItem to populate the new item - do it manually, use reflection, or however you prefer
// I'm using ValueInjecter and I also set the Id to zero because it maps the old Id
newCollectionItem.MyPartRecordWithCollection = building; // create relationship between the collection item and the new part record
building.Record.ContentItemRecord = existing.Record.ContentItemRecord;
building.Record.ContentItemVersionRecord = existing.Record.ContentItemVersionRecord;
building.Record.Collection.Add(newCollectionItem);
}
}
}
It is just a work around though. You probably wouldn't want to create a custom storage filter with copy logic for every part that has a relationship.
|