Open
Description
Changing type of primary key column also switches key generator. This can cause problems in case when switching is from more usable generator to less usable one. Possible scenario is below.
If original model looks like so (V1):
[HierarchyRoot]
public class IntPkEntity : Entity
{
[Field, Key]
public int Id { get; private set; }
[Field]
public DateTime CreationDate { get; set; }
}
[HierarchyRoot]
public class LongPkEntity : Entity
{
[Field, Key]
public long Id { get; private set; }
[Field]
public DateTime CreationDate { get; set; }
}
[HierarchyRoot]
public class TypeSwithchingEntity : Entity
{
[Field, Key]
public int Id { get; private set; }
[Field]
public DateTime CreationDate { get; set; }
}
and we upgrade primary key of one type to long (V2)
[HierarchyRoot]
public class TypeSwithchingEntity : Entity
{
[Field, Key]
public long Id { get; private set; }
[Field]
public DateTime CreationDate { get; set; }
}
then we can face problem shown in the test
[Test]
public void MainTest()
{
var initConfig = GetDomainConfiguration();
initConfig.Types.Register(typeof(V1.IntPkEntity));
initConfig.Types.Register(typeof(V1.LongPkEntity));
initConfig.Types.Register(typeof(V1.TypeSwithchingEntity));
initConfig.UpgradeMode = DomainUpgradeMode.Recreate;
using (var domain = Domain.Build(initConfig))
using (var session = domain.OpenSession())
using (var tx = session.OpenTransaction()) {
for (var i = 0; i < 512; i++) { // int generator is used more frequently
_ = new V1.IntPkEntity() { CreationDate = DateTime.UtcNow };
_ = new V1.TypeSwithchingEntity() { CreationDate = DateTime.UtcNow };
}
for (var i = 0; i < 128; i++) {
_ = new V1.LongPkEntity() { CreationDate = DateTime.UtcNow };
}
for (var i = 0; i < 128; i++) {
_ = new V1.TypeSwithchingEntity() { CreationDate = DateTime.UtcNow };
}
tx.Complete();
}
var upgradeConfig = GetDomainConfiguration();
upgradeConfig.Types.Register(typeof(V2.IntPkEntity));
upgradeConfig.Types.Register(typeof(V2.LongPkEntity));
upgradeConfig.Types.Register(typeof(V2.TypeSwithchingEntity));
upgradeConfig.UpgradeMode = DomainUpgradeMode.PerformSafely;
using (var domain = Domain.Build(upgradeConfig))
using (var session = domain.OpenSession())
using (var tx = session.OpenTransaction()) {
_ = new V2.TypeSwithchingEntity() { CreationDate = DateTime.UtcNow };
_ = new V2.TypeSwithchingEntity() { CreationDate = DateTime.UtcNow };
session.SaveChanges();
}
}
After successful upgrade any new TypeSwitchingEntity
may intersect with existing rows in table.
I'm pretty sure we should not allow such things to happen.