per-samuelsson / Misc

Just anything - snippets, docs that are are WIP, etc
0 stars 0 forks source link

Dropping synonyms #6

Open per-samuelsson opened 6 years ago

per-samuelsson commented 6 years ago

The very basics

With synonym

[Database] public class Person {
  public string Name { get; set; }
  public Person Friend;
}

[Database] public class BestFriend : Person {
  SynonymousTo("Friend")]
  public BestFriend Besty;
}

class Program {

    static void Main() {
        Db.Transact(() => {
            var besty = Db.SQL<BestFriend>("SELECT b FROM BasicWithSynonym.BestFriend b").FirstOrDefault();
            if (besty == null) {
                var bill = new BestFriend() { Name = "Bill" };
                var bull = new BestFriend() { Name = "Bull" };
                bill.Besty = bull;

                var piff = new BestFriend() { Name = "Piff" };
                var puff = new BestFriend() { Name = "Puff" };
                piff.Friend = puff;

                Console.WriteLine("Is Puff Piffs best friend? {0}", piff.Besty?.Equals(puff));
            }
        });
    }
}

When bound, we have metadata such as:

select * from Starcounter.Internal.Metadata.RawColumn c where c.Table.Name = 'bestfriend'

image

Doing this query produce expected result ("Bull") and below queryplan:

select f.Besty.Name from BasicWithSynonym.bestfriend f where f.Besty.Name = 'Bull'

Queryplan:

Tables(
 0 = BasicWithSynonym.BestFriend
 1 = BasicWithSynonym.BestFriend
)
Projection(
 0 = 
  StringPath(
   ObjectProperty(0, Besty)
   StringProperty(-1, Name)
  )
)
Join(
 Inner
 FullTableScan(
  BasicWithSynonym.BestFriend
  0
  LogicalValue(TRUE)
  Ascending
 )
 ReferenceLookup(
  1
  ObjectProperty(0, Besty)
  ComparisonString(
   Equal
   StringProperty(1, Name)
   StringLiteral(Bull)
  )
 )
)

Without synonym

[Database] public class Person {
  public string Name { get; set; }
  public Person Friend;
}

[Database] public class BestFriend : Person {
  public BestFriend Besty {
    get { return (BestFriend) Friend; }
    set { Friend = value; }
  }
}

class Program {

    static void Main() {
        Db.Transact(() => {
            var besty = Db.SQL<BestFriend>("SELECT b FROM BasicWithoutSynonym.BestFriend b").FirstOrDefault();
            if (besty == null) {
                var bill = new BestFriend() { Name = "Bill" };
                var bull = new BestFriend() { Name = "Bull" };
                bill.Besty = bull;

                var piff = new BestFriend() { Name = "Piff" };
                var puff = new BestFriend() { Name = "Puff" };
                piff.Friend = puff;

                Console.WriteLine("Is Puff Piffs best friend? {0}", piff.Besty?.Equals(puff));
            }
        });
    }
}

When bound, we have metadata such as:

select c.* from Starcounter.Internal.Metadata.RawColumn c where c.Table.FullName = 'BasicWithoutSynonym.BestFriend'

image

And query:

select f.Name from BasicWithoutSynonym.bestfriend f where f.Besty.Name = 'Bull'

Queryplan

Tables(
 0 = BasicWithoutSynonym.BestFriend
 1 = BasicWithoutSynonym.BestFriend
)
Projection(
 0 = 
  StringProperty(0, Name)
)
Join(
 Inner
 FullTableScan(
  BasicWithoutSynonym.BestFriend
  0
  LogicalValue(TRUE)
  Ascending
 )
 ReferenceLookup(
  1
  ObjectProperty(0, Besty)
  ComparisonString(
   Equal
   StringProperty(1, Name)
   StringLiteral(Bull)
  )
 )
)
per-samuelsson commented 6 years ago

Tested changing above use case with synonym and changed synonym to a property (variant below) in a populated database, restarted and made some queries. Everything work as expected.

per-samuelsson commented 6 years ago

Migrating usage of [SynonymousTo] (raw material)

Recommended practices. The general:

Field with same data type

Before

[Database] public class Foo {
  public string Bar;

  [SynonymousTo("Bar")]
  public string Fubar;
}

After

[Database] public class Foo {
  public string Bar { get; set; }  // <-- Strongly adviced: change to property instead of field

  public string Fubar {
    get { return Bar; }
    set { Bar = value; }
}

Field with narrowed data type

Before

[Database] public class Foo {
  public Foo Bar;

  [SynonymousTo("Bar")]
  public Narrowed Fubar;
}
[Database] public class Narrowed : Foo {}

After

[Database] public class Foo {
  public Foo Bar { get; set; }  // <-- Strongly adviced: change to property instead of field

  public Narrowed Fubar {
    get { return (Narrowed) Bar; }
    set { Bar = value; }
}
[Database] public class Narrowed : Foo {}

Read-only synonym pattern (used by Society Objects frequently)

Before

[Database] public class Foo {
  public string Bar;

  [SynonymousTo("Bar")]
  public readonly string Fubar;
}

After

[Database] public class Foo {
  public string Bar { get; set; }  // <-- Strongly adviced: change to property instead of field

  public string Fubar {
    get { return Bar; }
}