Hello again Anton.
As I said, type movements are not easy to implement. You need write it manually.
Correct way to do what you need is bellow. I added some another fields and types in model.
So, first model - model we upgrade from:
namespace ModelV1
{
[HierarchyRoot]
[Serializable]
public class TestEntity : Entity
{
[Key]
[Field(Nullable = false)]
public Guid Id { get; private set; }
[Field]
public string TestField { get; set; }
}
[Serializable]
public class TestEntity1 : TestEntity
{
[Field]
public string TestEntityField { get; set; }
}
[Serializable]
public class TestEntity11 : TestEntity1
{
[Field]
public TestEntity1 ReferenceField { get; set; }
}
[Serializable]
public class TestEntity2 : TestEntity
{
[Field]
public string TestEntity2Field { get; set; }
}
[Serializable]
[HierarchyRoot]
public class TestEntity3 : Entity
{
[Key, Field]
public Guid Id { get; set; }
[Field]
public TestEntity11 TestEntity11 { get; set; }
}
}
And second model - model we upgrade to:
namespace ModelV2
{
[HierarchyRoot]
[Serializable]
public class TestEntity : Entity
{
[Key]
[Field(Nullable = false)]
public Guid Id { get; private set; }
[Field]
public string TestField { get; set; }
}
[Serializable]
public class TestEntity1 : TestEntity
{
[Field]
public string TestEntityField { get; set; }
}
[Serializable]
[Recycled("ModelV1.TestEntity11")]
public class OldTestEntity11 : TestEntity1
{
[Field]
public TestEntity1 ReferenceField { get; set; }
}
[Serializable]
public class TestEntity11 : TestEntity2
{
[Field]
public TestEntity1 ReferenceField { get; set; }
}
[Serializable]
public class TestEntity2 : TestEntity
{
[Field]
public string TestEntity2Field { get; set; }
}
[Serializable]
[HierarchyRoot]
public class TestEntity3 : Entity
{
[Key, Field]
public Guid Id { get; set; }
[Field]
[Recycled("TestEntity11"), Obsolete]
public OldTestEntity11 OldTestEntity11 { get; set; }
[Field]
public TestEntity11 TestEntity11 { get; set; }
}
}
As you see, I renamed TestEntity11 to OldTestEntity11 and marked it by [Recycled] attribute. Also I wrote new TestEntity11 which is ancestor of TestEntity2 now. Note that I added another referencing field to new TestEntity into TestEntity3 class. I didn't remove old field and marked it by [Recycled] attribute too.
Now we need to add upgrade handler which copies data from old TestEntity11 to new TestEntity:
public class CustomUpgradeHandler : UpgradeHandler
{
public override bool CanUpgradeFrom(string oldVersion)
{
return true;
}
public override void OnUpgrade()
{
// we have old and new TestEntity11 both in here
// and we can do something with them.
// we need map from old IDs to new Entities
var testEntity11Map = new Dictionary<guid, testentity11="">();
// we get old entities and create new entity for every single old entity
var oldTestEntity11s = Session.Demand().Query.All<OldTestEntity11>();
var entity3s = Session.Demand().Query.All<TestEntity3>();
foreach (var oldTestEntity in oldTestEntity11s) {
var testEntity = new TestEntity11() {
ReferenceField = oldTestEntity.ReferenceField,
TestField = oldTestEntity.TestField,
TestEntity2Field = oldTestEntity.TestEntityField // probably, I don't know specific of your model. Let it be.
};
// creating map
testEntity11Map.Add(oldTestEntity.Id, testEntity);
}
// TestEntity3 has reference to TestEntity11
// and we remap from old to new TestEntity11 using our map;
foreach (var order in entity3s) {
order.TestEntity11 = testEntity11Map[order.OldTestEntity11.Id];
}
// also you can remove all old TestEntity11 after remapping all references.
// I think it is easy now.
}
}
After upgrade you will not have recycled types and fields and all data you need will be transformed correctly (if you will write it correctly, of course).
And domain configurations for first and second domains.
First:
var domainConfiguration = new DomainConfiguration("sqlserver://localhost/DO40-Tests");
domainConfiguration.Types.Register(typeof (TestEntity));
domainConfiguration.Types.Register(typeof (TestEntity1));
domainConfiguration.Types.Register(typeof (TestEntity11));
domainConfiguration.Types.Register(typeof (TestEntity2));
domainConfiguration.Types.Register(typeof (TestEntity3));
domainConfiguration.UpgradeMode = DomainUpgradeMode.Recreate;
Second:
var domainConfiguration = new DomainConfiguration("sqlserver://localhost/DO40-Tests");
domainConfiguration.Types.Register(typeof (NewModel.TestEntity));
domainConfiguration.Types.Register(typeof (NewModel.TestEntity1));
domainConfiguration.Types.Register(typeof (NewModel.TestEntity11));
domainConfiguration.Types.Register(typeof (NewModel.TestEntity2));
domainConfiguration.Types.Register(typeof (NewModel.TestEntity3));
domainConfiguration.Types.Register(typeof (NewModel.OldTestEntity11));
domainConfiguration.Types.Register(typeof (NewModel.CustomUpgradeHandler));
domainConfiguration.UpgradeMode = DomainUpgradeMode.PerformSafely;
answered
Jun 08 '15 at 09:38
Alexey Kulakov
772●2●5
Hello Anton. Changing hierarchy is not simple operation. You should change it more carefully with creation of new class and then copying data from old to new table. I will create example based on your hierarchy model and post it as answer