Пример #1
0
        public void TestLocking()
        {
            switch (Startup.ServerType)
            {
            case Data.Driver.DbServerType.SQLite:
                return; //do not support locks
            }
            if (File.Exists(_logFileName))
            {
                File.Delete(_logFileName);
            }
            _app         = new LockTestApp();
            _app.LogPath = _logFileName;
            Startup.ActivateApp(_app);

            //Run with locks - we should see no errors
            int ThreadCount = 30;
            int UpdateCount = 50;

            RunTests(LockType.SharedRead, LockType.ForUpdate, ThreadCount, UpdateCount);
            Assert.AreEqual(0, _updateErrorCount, "Expected no update errors");
            Assert.AreEqual(0, _sumErrorCount, "Expected no sum errors");
            Trace.WriteLine("Lock test completed");

            //Uncomment to see errros when run without locks; commented to save time of running unit tests

            /*
             * //Run without locks - we should see multiple errors;
             * RunTests(LockType.None, LockType.None, 60, 50);
             * var note = " Note: this can happen occasionally, ignore.";
             * Assert.IsTrue(_updateErrorCount > 0, "Expected some update errors." + note);
             * Assert.IsTrue(_sumErrorCount > 0, "Expected some sum errors." + note);
             */
        }//method
Пример #2
0
        public void TestLocking()
        {
            switch (Startup.ServerType)
            {
            case Data.Driver.DbServerType.SqlCe:
            case Data.Driver.DbServerType.Sqlite:
                return; //do not support locks
            }
            if (File.Exists(_logFileName))
            {
                File.Delete(_logFileName);
            }
            Startup.DropSchemaObjects("lck");
            _app = new LockTestApp();
            Startup.ActivateApp(_app);

            //Run with locks - we should see no errors
            RunTests(LockOptions.SharedRead, LockOptions.ForUpdate, 30, 50);
            Assert.AreEqual(0, _updateErrorCount, "Expected no update errors");
            Assert.AreEqual(0, _sumErrorCount, "Expected no sum errors");

            //Uncomment to see errros when run without locks; commented to save time of running unit tests

            /*
             * //Run without locks - we should see multiple errors; using more threads to get errors for sure
             * RunTests(LockOptions.None, LockOptions.None, 40, 50);
             * var note = " Note: this can happen occasionally, ignore.";
             * Assert.IsTrue(_updateErrorCount > 0, "Expected some update errors." + note);
             * Assert.IsTrue(_sumErrorCount > 0, "Expected some sum errors." + note);
             */
        }//method
Пример #3
0
        public void RunTestIdentityWithSelfRefEntities()
        {
            _app = new IdentityTestsEntityApp();
            Startup.ActivateApp(_app);
            //if(Startup.ServerType == Data.Driver.DbServerType.SQLite)
            DeleteAllData();
            var session = _app.OpenSession();

            // Create 3-level tree and save it
            var node1 = session.NewNode("N1");

            // level 2
            var node11 = session.NewNode("N11", node1);
            var node12 = session.NewNode("N12", node1);
            var node13 = session.NewNode("N13", node1);

            // level 3
            var node111 = session.NewNode("N1111", node11);
            var node112 = session.NewNode("N1112", node11);
            var node121 = session.NewNode("N1121", node12);
            var node122 = session.NewNode("N1122", node12);
            var node131 = session.NewNode("N1131", node13);
            var node132 = session.NewNode("N1132", node13);

            DataUtility.RandomizeRecordOrder(session);
            session.SaveChanges();

            // test passed if it executed without exceptions
            Assert.IsTrue(true, "never happens");
        }
Пример #4
0
        public void RunTest(bool batchMode)
        {
            _app = new IdentityRefTestEntityApp();
            Startup.ActivateApp(_app);
            //if(Startup.ServerType == Data.Driver.DbServerType.SQLite)
            DeleteAllData();
            // We create session this way to set the batch mode flag
            var            ctx     = new OperationContext(_app);
            IEntitySession session = new EntitySession(ctx,
                                                       options: batchMode ? EntitySessionOptions.None : EntitySessionOptions.DisableBatchMode);

            var john   = session.NewUser("john");
            var post1  = john.NewPost("john post 1", 1);
            var post2  = john.NewPost("john post 2", 2);
            var post3  = john.NewPost("john post 3", 3);
            var ben    = session.NewUser("ben");
            var post1b = ben.NewPost("ben post 1", 1);
            var post2b = ben.NewPost("ben post 2", 2);
            var post3b = ben.NewPost("ben post 3", 3);

            session.SaveChanges();
            //Check that Identity values immediately changed to actual positive values loaded from database
            Assert.IsTrue(post1.OrderId > 0, "Invalid OrderID - expected positive value.");
            Assert.IsTrue(post2.OrderId > 0, "Invalid OrderID - expected positive value.");
            Assert.IsTrue(post3.OrderId > 0, "Invalid OrderID - expected positive value.");

            //Start new session, load all and check that IDs and relationships are correct
            session = _app.OpenSession();
            var posts = session.EntitySet <IUserPost>().ToList();

            foreach (var post in posts)
            {
                Assert.IsTrue(post.OrderId > 0);
            }
        }//method
Пример #5
0
        public void TestSequences()
        {
            //Only MS SQL and Postgres support sequences
            switch (Startup.ServerType)
            {
            case Data.Driver.DbServerType.MsSql:
            case Data.Driver.DbServerType.Postgres:
                break;

            default: return;
            }
            _app = new SequenceTestApp();
            Startup.ActivateApp(_app);
            var session = _app.OpenSession();

            var valueOne = session.Select(() => 1);

            Assert.AreEqual(1, valueOne);

            var idSeq = _app.Model.FindSequence("IdSequence");

            for (int i = 0; i < 3; i++)
            {
                var seqValue = session.GetSequenceNextValue(idSeq);
            }

            //using it in SQL query
            var seqQueryList = session.EntitySet <IPerson>().Select(p => new { p.Name, AltId = idSeq.NextValue() }).ToList();

            var john = session.NewEntity <IPerson>();

            john.Name = "Jack M";
            var car1 = session.NewEntity <ICar>();

            car1.Model = "Beatle";
            car1.Owner = john;
            var car2 = session.NewEntity <ICar>();

            car2.Model = "Legacy";
            car2.Owner = john;
            //Check that Identity values immediately changed to actual positive values loaded from database
            Assert.IsTrue(john.Id > 0, "Invalid person ID - expected positive value.");
            Assert.IsTrue(car1.Id > 0, "Invalid car1 ID - expected positive value.");
            Assert.IsTrue(car2.Id > 0, "Invalid car2 ID - expected positive value.");
            session.SaveChanges();

            //Start new session, load all and check that IDs and relationships are correct
            session = _app.OpenSession();
            var persons = session.GetEntities <IPerson>().ToList();

            john = persons[0];
            var cars = session.GetEntities <ICar>().ToList();

            car1 = cars[0];
            car2 = cars[1];
            Assert.IsTrue(john.Id > 0 && car1.Id > 0 && car2.Id > 0, "IDs expected to become > 0 after saving.");
            Assert.IsTrue(car1.Owner == john, "Owner expected to be John");
            Assert.IsTrue(car2.Owner == john, "Owner expected to be John");
        } //method
Пример #6
0
 public void Init()
 {
     if (_app == null)
     {
         _app = new MiscLinqEntityApp();
         Startup.ActivateApp(_app);
     }
 }
Пример #7
0
 public void Init()
 {
     if (_app == null)
     {
         Startup.DropSchemaObjects("misc");
         _app = new MiscTestsEntityApp();
         Startup.ActivateApp(_app);
     }
 }
Пример #8
0
        public void TestOneToOneRef()
        {
            _app = new OneToOneEntityApp();
            Startup.DropSchemaObjects("one");
            Startup.ActivateApp(_app);
            var session = _app.OpenSession();

            //initial setup
            session = _app.OpenSession();
            var header = session.NewEntity <IDocHeader>();

            header.Name = "Doc1";
            var det = session.NewEntity <IDocDetails>();

            det.Details = "Some details";
            det.Header  = header;
            var cm = session.NewEntity <IDocComments>();

            cm.Details = det;
            cm.Comment = "Some comment";
            session.SaveChanges();
            //test LINQ queries - used to fail
            var query  = session.EntitySet <IDocComments>().Where(dc => dc.Details == det);
            var cmList = query.ToList();

            Assert.IsTrue(cmList.Count == 1, "Expected 1 comment.");
            //Test can delete method, also used to fail with one-to-one
            Type[] bt;
            var    canDel = session.CanDeleteEntity(det, out bt);

            Assert.IsFalse(canDel, "Expected CanDelete = false.");

            // test [OneToOne] entity
            // IDocHeader.Details is 'back-ref' property, marked with OneToOne attribute
            // IDocHeader.Details2 is similar, but we did not create IDocDetails2 record, so it should be null
            var docId = header.Id;

            session = _app.OpenSession();
            var doc  = session.GetEntity <IDocHeader>(docId);
            var det1 = doc.Details;

            Assert.IsNotNull(det1, "Expected Details");
            var det2 = doc.Details2;

            Assert.IsNull(det2, "Expected Details2 = null");
            //do it again, to check it is correctly cached in record (so it does not blow up)
            det1 = doc.Details;
            det2 = doc.Details2;
            // test using [OneToOne] references in Linq
            session = _app.OpenSession();
            var q2   = session.EntitySet <IDocHeader>().Where(h => h.Details.Details == "Some details");
            var docs = q2.ToList();

            Assert.AreEqual(1, docs.Count, "Expected Doc header");
        } //method
Пример #9
0
        public void TestSequences()
        {
            //Only MS SQL and Postgres support sequences
            switch (Startup.ServerType)
            {
            case Data.Driver.DbServerType.MsSql:
            case Data.Driver.DbServerType.Postgres: break;

            default: return;
            }
            _app = new SequenceTestApp();
            Startup.DropSchemaObjects("seq");
            Startup.ActivateApp(_app);
            var session = _app.OpenSession();

            for (int i = 0; i < 10; i++)
            {
                var intValue  = session.GetSequenceNextValue <int>("seq.IntSequence");
                var longValue = session.GetSequenceNextValue <long>("seq.LongSequence");
            }

            var john = session.NewEntity <IPerson>();

            john.Name = "Jack M";
            var car1 = session.NewEntity <ICar>();

            car1.Model = "Beatle";
            car1.Owner = john;
            var car2 = session.NewEntity <ICar>();

            car2.Model = "Legacy";
            car2.Owner = john;
            //Check that Identity values immediately changed to actual positive values loaded from database
            Assert.IsTrue(john.Id > 0, "Invalid person ID - expected positive value.");
            Assert.IsTrue(car1.Id > 0, "Invalid car1 ID - expected positive value.");
            Assert.IsTrue(car2.Id > 0, "Invalid car2 ID - expected positive value.");
            session.SaveChanges();

            //Start new session, load all and check that IDs and relationships are correct
            session = _app.OpenSession();
            var persons = session.GetEntities <IPerson>().ToList();

            john = persons[0];
            var cars = session.GetEntities <ICar>().ToList();

            car1 = cars[0];
            car2 = cars[1];
            Assert.IsTrue(john.Id > 0 && car1.Id > 0 && car2.Id > 0, "IDs expected to become > 0 after saving.");
            Assert.IsTrue(car1.Owner == john, "Owner expected to be John");
            Assert.IsTrue(car2.Owner == john, "Owner expected to be John");
        } //method
Пример #10
0
        public void TestIdentityColumns(bool batchMode)
        {
            _app = new IdentityTestsEntityApp();
            Startup.ActivateApp(_app);
            //if(Startup.ServerType == Data.Driver.DbServerType.SQLite)
            DeleteAllData();
            // We create session this way to set the batch mode flag
            var            ctx     = new OperationContext(_app);
            IEntitySession session = new EntitySession(ctx,
                                                       options: batchMode ? EntitySessionOptions.None : EntitySessionOptions.DisableBatchMode);
            var john = session.NewEntity <IPerson>();

            john.Name = "John S";
            //john.Name = "Джон Ш"; //Russian
            var car1 = session.NewEntity <ICar>();

            car1.Model   = "Beatle";
            car1.Owner   = john;
            car1.CoOwner = null;
            var car2 = session.NewEntity <ICar>();

            car2.Model = "Explorer";
            car2.Owner = john;
            Assert.IsTrue(car1.Id < 0, "Car ID is expected to be <0 before saving.");
            session.SaveChanges();
            //Check that Identity values immediately changed to actual positive values loaded from database
            Assert.IsTrue(john.Id > 0, "Invalid person ID - expected positive value.");
            Assert.IsTrue(car1.Id > 0, "Invalid car1 ID - expected positive value.");
            Assert.IsTrue(car2.Id > 0, "Invalid car2 ID - expected positive value.");

            //Start new session, load all and check that IDs and relationships are correct
            session = _app.OpenSession();
            john    = session.EntitySet <IPerson>().Where(p => p.Name == "John S").Single();
            var cars = session.GetEntities <ICar>().ToList();

            car1 = cars[0];
            car2 = cars[1];
            Assert.IsTrue(john.Id > 0 && car1.Id > 0 && car2.Id > 0, "IDs expected to become > 0 after saving.");
            Assert.IsTrue(car1.Owner == john, "Owner expected to be John");
            Assert.IsTrue(car2.Owner == john, "Owner expected to be John");

            // Testing list.Contains with long (bigint) values, used to fail for SQL Server
            var longArray = new long[] { long.MaxValue - 10, long.MaxValue - 9, long.MaxValue - 8 };
            // we just test that this does not blow up
            var someCars = session.EntitySet <ICar>().Where(c => longArray.Contains(c.Id)).ToList();
            var sql      = session.GetLastCommand().CommandText;

            Assert.AreEqual(0, someCars.Count);
        }//method
Пример #11
0
            public void TestModuleIntegration()
            {
                var schema = "usr";

                Startup.DropSchemaObjects(schema); //start from scratch

                // Runs integrated app by Randy
                _app = new EntityApp();
                var area        = _app.AddArea(schema);
                var persModule  = new Bob.PersonModule(area);
                var loginModule = new Alice.LoginModule(area, typeof(IPersonExt));

                // Now replace original entities with new interfaces;
                // Alice's IUserStub is already replaced by Randy's IPersonExt.
                _app.ReplaceEntity(typeof(Alice.ILogin), typeof(IAppLogin));
                _app.ReplaceEntity(typeof(Bob.IPerson), typeof(IPersonExt));
                // activate
                Startup.ActivateApp(_app);

                //Test the resulting solution
                var session = _app.OpenSession();
                var pers    = session.NewEntity <IPersonExt>();

                pers.FirstName = "John";
                pers.LastName  = "Dow";
                pers.BirthDate = new DateTime(1970, 5, 1);
                pers.Gender    = Gender.Male;
                var login   = session.NewEntity <IAppLogin>();
                var loginId = login.Id;

                login.User           = pers;
                login.UserName       = "******";
                login.FriendlyName   = "JohnD";
                login.PasswordHash   = 123;
                login.EmployeeNumber = "E111";
                session.SaveChanges();

                //Let's try to login the user we created using Alice's method
                session = _app.OpenSession();
                var johnLogin = Alice.LoginModule.Login(session, "johnd", 123);
                var cmd       = session.GetLastCommand();

                Assert.IsNotNull(johnLogin, "Login failed");
            } //method
Пример #12
0
        public void TestIdentityColumns(bool batchMode)
        {
            _app = new IdentityTestsEntityApp();
            Startup.ActivateApp(_app);
            //if(Startup.ServerType == Data.Driver.DbServerType.SQLite)
            DeleteAllData();
            // We create session this way to set the batch mode flag
            var            ctx     = new OperationContext(_app);
            IEntitySession session = new EntitySession(ctx,
                                                       options: batchMode ? EntitySessionOptions.None : EntitySessionOptions.DisableBatchMode);
            var john = session.NewEntity <IPerson>();

            john.Name = "John S";
            var car1 = session.NewEntity <ICar>();

            car1.Model   = "Beatle";
            car1.Owner   = john;
            car1.CoOwner = null;
            var car2 = session.NewEntity <ICar>();

            car2.Model = "Explorer";
            car2.Owner = john;
            Assert.IsTrue(car1.Id < 0, "Car ID is expected to be <0 before saving.");
            session.SaveChanges();
            //Check that Identity values immediately changed to actual positive values loaded from database
            Assert.IsTrue(john.Id > 0, "Invalid person ID - expected positive value.");
            Assert.IsTrue(car1.Id > 0, "Invalid car1 ID - expected positive value.");
            Assert.IsTrue(car2.Id > 0, "Invalid car2 ID - expected positive value.");

            //Start new session, load all and check that IDs and relationships are correct
            session = _app.OpenSession();
            john    = session.EntitySet <IPerson>().Where(p => p.Name == "John S").Single();
            var cars = session.GetEntities <ICar>().ToList();

            car1 = cars[0];
            car2 = cars[1];
            Assert.IsTrue(john.Id > 0 && car1.Id > 0 && car2.Id > 0, "IDs expected to become > 0 after saving.");
            Assert.IsTrue(car1.Owner == john, "Owner expected to be John");
            Assert.IsTrue(car2.Owner == john, "Owner expected to be John");
        }//method
Пример #13
0
        public void TestIdentityInLargeBatch()
        {
            _app = new IdentityTestsEntityApp();
            Startup.ActivateApp(_app);
            // For SQLite objects are not dropped (FK problems), so we need to instead delete all data
            if (Startup.ServerType == Data.Driver.DbServerType.SQLite)
            {
                DeleteAllData();
            }
            var sqlDialect     = _app.GetDefaultDatabase().DbModel.Driver.SqlDialect;
            var saveParamCount = sqlDialect.MaxParamCount;

            sqlDialect.MaxParamCount = 20; //to cause update batch split into multiple commands
            var session = _app.OpenSession();
            // add 50 owners, then 200 cars with random owners
            // our goal is to create update set with inserts of linked entities with identity pk/fk
            // we test how identity values are carried between commands (from IPerson.Id to ICar.OwnerId)
            var owners = new List <IPerson>();
            var rand   = new Random();

            for (int i = 0; i < 50; i++)
            {
                var owner = session.NewEntity <IPerson>();
                owner.Name = "Owner" + i;
                owners.Add(owner);
            }
            for (int i = 0; i < 100; i++)
            {
                var car = session.NewEntity <ICar>();
                car.Model = "Model" + i;
                car.Owner = owners[rand.Next(owners.Count)];
            }
            try {
                session.SaveChanges(); //we just test that it succeeds
            } finally {
                //revert max param count back to normal - to avoid disturbing other tests
                sqlDialect.MaxParamCount = saveParamCount;
            }
        }
Пример #14
0
        private void TestSchemaUpdateImpl()
        {
            Startup.DropSchemaObjects(SchemaName);
            var supportsClustIndex = Startup.Driver.Supports(DbFeatures.ClusteredIndexes);

            //version 1 of model/schema
            {
                var app = new EntityAppV1();

                Startup.ActivateApp(app); //updates schema

                // Load DbModel and verify it is correct
                var dbModel = Startup.LoadDbModel(SchemaName, app.SystemLog);
                Assert.AreEqual(6, dbModel.Tables.Count(), "Expected 6 tables."); //2 tables in DbInfo + 4 tables in our module
                var parTable = dbModel.GetTable(SchemaName, "ParentEntity");
                Assert.AreEqual(8, parTable.Columns.Count, "Invalid number of columns in parent table.");
                var keyCount = CountKeys(parTable);
                //Keys: PK, FK to IEntityToDelete, index on FK to IEntityToDelete, index on IntProp,StringProp, (ClusteredIndex?)
                Assert.AreEqual(5, keyCount, "Invalid # of keys in parent table.");

                if (supportsClustIndex)
                {
                    var parCI = parTable.Keys.First(k => k.KeyType.IsSet(KeyType.ClusteredIndex));
                    Assert.AreEqual(1, parCI.KeyColumns.Count, "Invalid number of fields in clustered index.");
                }

                //child entity
                var childTable = dbModel.GetTable(SchemaName, "ChildEntity");
                Assert.AreEqual(5, childTable.Columns.Count, "Invalid number of columns in child table.");
                // some servers like MySql create FK and Index on it under the same name. When loading, such a key should be marked with 2 flags
                // so let's count these separately; should be 5: PK + 2 foreign keys + 2 indexes on FK
                keyCount = CountKeys(childTable);
                Assert.AreEqual(5, keyCount, "Invalid # of keys in child table.");

                //Create a few records
                var session = app.OpenSession();
                var parent  = session.NewEntity <EntityModuleV1.IParentEntity>();
                parent.IntProp             = 4;
                parent.StringProp          = "Some string";
                parent.SingleProp          = 4.56f;
                parent.DoubleProp          = 5.67;
                parent.IntPropWithDefault  = 567;
                parent.StringProp2_OldName = "Old string";
                var child = session.NewEntity <EntityModuleV1.IChildEntity>();
                child.Parent            = parent;
                child.ParentRefToDelete = parent;
                child.Name = "Child name";
                var entToDelete = session.NewEntity <EntityModuleV1.IEntityToDelete>();
                entToDelete.Name         = "some-name";
                parent.EntityToDeleteRef = entToDelete;
                session.SaveChanges();
                app.Shutdown();
            }

            //Now change to version 2 ================================================================
            {
                var app = new EntityAppV2();
                Startup.ActivateApp(app, dropUnknownTables: true);

                //At this point the schema should have been updated; let's check it
                // Load DbModel and verify it is correct
                var dbModel = Startup.LoadDbModel(SchemaName, app.SystemLog);
                Assert.AreEqual(6, dbModel.Tables.Count(), "Expected 6 tables after update.");
                var parTable = dbModel.GetTable(SchemaName, "ParentEntity");
                Assert.AreEqual(7, parTable.Columns.Count, "Invalid number of columns in parent table after schema update.");
                Assert.AreEqual(3, parTable.Keys.Count, //PK, Clustered index, index on IntProp,StringProp
                                "Invalid # of keys in parent table after update.");
                if (supportsClustIndex)
                {
                    //SQL CE does not support clustered indexes
                    var parCI = parTable.Keys.First(k => k.KeyType.IsSet(KeyType.ClusteredIndex));
                    Assert.AreEqual(2, parCI.KeyColumns.Count, "Invalid number of fields in clustered index."); //
                }
                //child entity
                var childTable = dbModel.GetTable(SchemaName, "ChildEntityRenamed");
                Assert.AreEqual(5, childTable.Columns.Count, "Invalid number of columns in child table after update.");
                var keyCount = CountKeys(childTable); // = 5:  Clustered PK, FK to parent, index on FK, FK to OtherParent, index on FK
                Assert.AreEqual(5, keyCount, "Invalid # of keys in child table after update.");
                //Check that post-upgrade action is executed - check records are added to INewTable
                var session          = app.OpenSession();
                var newTableEntCount = session.EntitySet <EntityModuleV2.INewTable>().Count();
                Assert.AreEqual(2, newTableEntCount, "Expected 2 entities in INewTable.");

                //  Now create model again, compare it and make sure no schema updates
                var ds          = app.GetDefaultDataSource();
                var dbUpdater   = new DbUpgradeManager(ds);
                var upgradeInfo = dbUpdater.BuildUpgradeInfo();
                // if we have upgrade scripts, this is error
                if (upgradeInfo.AllScripts.Count > 0)
                {
                    var strUpdates = upgradeInfo.AllScripts.GetAllAsText();
                    Debug.WriteLine("Detected updates when no schema changes should be present:");
                    Debug.WriteLine(strUpdates);
                    Assert.IsTrue(false, "Schema changes count should be zero.");
                }
                app.Flush();
            }
        }//method
Пример #15
0
 public void Init()
 {
     _app = new UpdateSortEntityApp();
     Startup.ActivateApp(_app, dropOldSchema: true);
 }
Пример #16
0
 public void Init()
 {
     _app = new DataTypesTestEntityApp();
     Startup.ActivateApp(_app);
 }
Пример #17
0
        //Separate implementation for SQLite. SQLite does not support column-modify, table-rename, etc.
        // So we try to account for these in this special version
        private void TestSchemaUpdateImplSQLite()
        {
            //Start from fresh copy of the database
            File.Copy("..\\..\\VitaTestSQLite.db", "VitaTestSQLite.db", overwrite: true);
            // Note - we have the flag AddSchemaToTableName for SQlite setup (default),
            //  so table names are prefixed with 'upd_'

            //version 1 of model/schema
            {
                var app = new EntityAppV1();
                Startup.ActivateApp(app); //updates schema

                // Load DbModel and verify it is correct
                var dbModel = Startup.LoadDbModel(SchemaName, app.SystemLog);
                Assert.AreEqual(6, dbModel.Tables.Count(), "Expected 4 tables.");
                var parTable = dbModel.GetTable(null, "upd_ParentEntity");
                Assert.AreEqual(8, parTable.Columns.Count, "Invalid number of columns in parent table.");
                var keyCount = CountKeys(parTable);
                //Keys: PK, FK to IEntityToDelete, index on FK to IEntityToDelete, index on IntProp,StringProp
                Assert.AreEqual(4, keyCount, "Invalid # of keys in parent table.");


                //child entity
                var childTable = dbModel.GetTable(SchemaName, "upd_ChildEntity");
                Assert.AreEqual(5, childTable.Columns.Count, "Invalid number of columns in child table.");
                // 3 - PK + 2FKs, no indexes on FKs
                Assert.AreEqual(3, childTable.Keys.Count, "Invalid # of keys in child table.");

                //Create a few records
                var session = app.OpenSession();
                var parent  = session.NewEntity <EntityModuleV1.IParentEntity>();
                parent.IntProp             = 4;
                parent.StringProp          = "Some string";
                parent.SingleProp          = 4.56f;
                parent.DoubleProp          = 5.67;
                parent.IntPropWithDefault  = 567;
                parent.StringProp2_OldName = "Old string";
                var child = session.NewEntity <EntityModuleV1.IChildEntity>();
                child.Parent            = parent;
                child.ParentRefToDelete = parent;
                child.Name = "Child name";
                var entToDelete = session.NewEntity <EntityModuleV1.IEntityToDelete>();
                entToDelete.Name         = "some-name";
                parent.EntityToDeleteRef = entToDelete;
                session.SaveChanges();
                app.Flush();
                app.Shutdown();
            }
            //Now change to version 2 ================================================================
            {
                var app = new EntityAppV2();
                Startup.ActivateApp(app, dropUnknownTables: true);

                //At this point the schema should have been updated; let's check it
                // Load DbModel and verify it is correct
                var dbModel = Startup.LoadDbModel(SchemaName, app.SystemLog);
                //Note that we still have 4 tables, EntityToDelete is not dropped because of incoming FK
                Assert.AreEqual(7, dbModel.Tables.Count(), "Expected 7 tables after update.");
                var parTable = dbModel.GetTable(SchemaName, "upd_ParentEntity");
                //NO support for dropping columns, so old columns are not deleted; instead of renaming a new column is added
                Assert.AreEqual(11, parTable.Columns.Count, "Invalid number of columns in parent table after schema update.");
                Assert.AreEqual(4, parTable.Keys.Count, //PK, FK->EntityToDelete, indexes (IntProp,StringProp), (StropProp,Id)
                                "Invalid # of keys in parent table after update.");
                //child entity
                var childTable = dbModel.GetTable(SchemaName, "upd_ChildEntity");
                Assert.AreEqual(6, childTable.Columns.Count, "Invalid number of columns in child table after update.");
                // = 3:  Clustered PK, FK to parent, index on FK
                Assert.AreEqual(3, childTable.Keys.Count, "Invalid # of keys in child table after update.");
                //Check that post-upgrade action is executed - check records are added to INewTable
                var session          = app.OpenSession();
                var newTableEntCount = session.EntitySet <EntityModuleV2.INewTable>().Count();
                Assert.AreEqual(2, newTableEntCount, "Expected 2 entities in INewTable.");

                // Now create model again, compare it and make sure no schema updates
                var ds          = app.GetDefaultDataSource();
                var upgradeMgr  = new DbUpgradeManager(ds);
                var upgradeInfo = upgradeMgr.BuildUpgradeInfo();
                if (upgradeInfo.AllScripts.Count > 0)
                {
                    var strUpdates = upgradeInfo.AllScripts.GetAllAsText();
                    Debug.WriteLine("Detected updates when no schema changes should be present:");
                    Debug.WriteLine(strUpdates);
                    Assert.IsTrue(false, "Schema changes count should be zero.");
                }
                app.Flush();
            }
        }