Hi,

We would like to add an extra layer to one of our class hierarchies. The configuration now is

Root <- ClassA <- ClassB

and should become

Root <- ClassNew <- ClassA <- ClassB

Can we somehow achieve this in the upgrader?

Regards Paul

asked Nov 13 '14 at 01:18

Paul%20Sinnema's gravatar image

Paul Sinnema
261888896


One Answer:

Hi Paul.

It's not to easy to do that in DO. The main problem that DO do not know how to fill new empty table, but without data it this table DBMS don't allow creation of 1-to-1 FK between Root and ClassNew and ClassNew and ClassA. But you can do that using trick. You can build domain without FKs, fill NewClass table by data and create FKs back. For example, we have two models. First model (which in database now, without changes, old model)


namespace ModelV1
{
  [HierarchyRoot]
  public abstract class BaseClass : Entity
  {
    [Field]
    [Key]
    public int Id { get; set; }

[Field]
public string SomeField { get; set; }

}

public class ClassA : BaseClass { [Field] public string SomeFieldOfClassA { get; set; } }

public class ClassB : ClassA { [Field] public string SomeFieldOfClassB { get; set; } } }

And second model (which has new class in hierarchy, the model we upgrade to)


namespace ModelV2
{
  [HierarchyRoot]
  public abstract class BaseClass : Entity
  {
    [Field]
    [Key]
    public int Id { get; set; }

    [Field]
    public string SomeField { get; set; }
  }

  public class NewClass : BaseClass
  {
    [Field]
    public string SomeFieldOfNewClass { get; set; }
  }

  public class ClassA : NewClass
  {
    [Field]
    public string SomeFieldOfClassA { get; set; }
  }

  public class ClassB : ClassA
  {
    [Field]
    public string SomeFieldOfClassB { get; set; }
  }
}

When i'll write v2.BaseClass class i'll mean BaseClass from ModelV2 namespace.

Now we are building domain without FKs. We using domain configuration like


var configuration = new DomainConfiguration("sqlserver://localhost/DO40-Tests?MultipleActiveResultSets=True");
configuration.Types.Register(typeof (v2.BaseClass));
configuration.Types.Register(typeof (v2.NewClass));
configuration.Types.Register(typeof (v2.ClassA));
configuration.Types.Register(typeof (v2.ClassB));
configuration.ForeignKeyMode = ForeignKeyMode.None;// Switch off FKs
configuration.UpgradeMode = DomainUpgradeMode.PerformSafely;

Now we are creating custom upgrade handler like


public class Upgrader : UpgradeHandler
    {
      public override bool CanUpgradeFrom(string oldVersion)
      {
        return true;
      }

      public override void OnPrepare()
      {
        using (var connection = new System.Data.SqlClient.SqlConnection("Data Source=localhost;Initial Catalog=DO40-Tests;Integrated Security=True;Persist Security Info=False;MultipleActiveResultSets=True")) {
          connection.Open();
          using (var command = connection.CreateCommand()) {
            command.CommandText =
              @"INSERT INTO [DO40-Tests].[dbo].[NewClass] (Id, TypeId)
                    SELECT Id, TypeId
                    FROM [DO40-Tests].[dbo].[BaseClass]";
            command.ExecuteNonQuery();
          }
          connection.Close();
        }
      }
    }

This upgrade handler copies data to NewClass table before domain building.

After that we are building domain with domain configuration like


var configuration = base.BuildConfiguration();
configuration.Types.Register(typeof(v2.BaseClass));
configuration.Types.Register(typeof(v2.NewClass));
configuration.Types.Register(typeof(v2.ClassA));
configuration.Types.Register(typeof(v2.ClassB));
configuration.Types.Register(typeof(v2.Upgrader));
configuration.UpgradeMode = DomainUpgradeMode.PerformSafely;

It creates FKs back if data in new table is correct. That's all. You can build domain in normal mode with configuration


var configuration = new DomainConfiguration("sqlserver://localhost/DO40-Tests?MultipleActiveResultSets=True");
configuration.Types.Register(typeof (v2.BaseClass));
configuration.Types.Register(typeof (v2.NewClass));
configuration.Types.Register(typeof (v2.ClassA));
configuration.Types.Register(typeof (v2.ClassB));
configuration.UpgradeMode = DomainUpgradeMode.PerformSafely;

answered Nov 14 '14 at 04:56

Alexey%20Kulakov's gravatar image

Alexey Kulakov
77225

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA