public void Insert_NonIdentityKey_MatchesExpected() { var mockDatabaseFactory = new Mock <IDatabaseContextFactory>(); var mockDatabaseContext = new Mock <IDatabaseContext>(); mockDatabaseFactory.Setup(factory => factory.Create()).Returns(mockDatabaseContext.Object); var repositoryAdapter = new Mock <IRepositoryAdapter>(); mockDatabaseContext.Setup(context => context.RepositoryAdapter).Returns(repositoryAdapter.Object); var definitionProvider = new DataAnnotationsDefinitionProvider(); repositoryAdapter.Setup(compiler => compiler.CreateInsertionStatement <DependentRow>()).Returns(string.Empty); repositoryAdapter.Setup(adapter => adapter.DefinitionProvider).Returns(definitionProvider); var databaseFactory = mockDatabaseFactory.Object; using (var target = new DatabaseRepositoryProvider(databaseFactory)) { var expected = new DependentRow { FakeDependentEntityId = 234, DependentIntegerValue = 4583, DependentTimeValue = DateTimeOffset.Now }; var actual = target.Insert(expected); Assert.AreSame(expected, actual); } }
/// <summary> /// Creates a fake complex row. /// </summary> /// <param name="withDependentEntity"> /// A value indicating whether to create the row with a dependent entity. /// </param> /// <returns> /// A new <see cref="ComplexFlatRow"/> instance. /// </returns> public static ComplexRaisedRow CreateFakeRaisedComplexRow(bool withDependentEntity) { var createdBy = new MultiReferenceRow { Description = MyString, FakeMultiReferenceEntityId = MyInt, UniqueName = MyString }; var fakeSubSubEntity = new SubSubRow { FakeSubSubEntityId = MyInt, UniqueName = MyString, Description = MyString }; var fakeSubEntity = new SubRow { FakeSubEntityId = MyInt, FakeSubSubEntityId = MyInt, SubSubEntity = fakeSubSubEntity, UniqueName = MyString, UniqueOtherId = MyShort, Description = MyString }; var modifiedBy = new MultiReferenceRow { FakeMultiReferenceEntityId = MyInt, Description = MyString, UniqueName = MyString }; var fakeDependentEntity = new DependentRow { FakeDependentEntityId = MyInt, DependentIntegerValue = MyInt, DependentTimeValue = MyDateTimeOffset }; return(new ComplexRaisedRow { CreatedBy = createdBy, UniqueName = MyString, FakeSubEntityId = MyInt, SubEntity = fakeSubEntity, ModifiedBy = modifiedBy, DependentEntity = withDependentEntity ? fakeDependentEntity : null, ModifiedTime = MyDateTimeOffset, Description = MyString, FakeEnumerationId = MyInt, CreationTime = MyDateTimeOffset, FakeOtherEnumerationId = MyInt, ComplexEntityId = MyInt }); }
public void Load_ListOfRows_DataMatchesExpected() { var target = new DataTableLoader <DependentRow>(new DataAnnotationsDefinitionProvider()); var dependentRows = new List <DependentRow> { new DependentRow { FakeDependentEntityId = 454, DependentIntegerValue = 3, DependentTimeValue = DateTimeOffset.MaxValue }, new DependentRow { FakeDependentEntityId = 455, DependentIntegerValue = 2, DependentTimeValue = DateTimeOffset.MinValue }, new DependentRow { FakeDependentEntityId = 456, DependentIntegerValue = 1, DependentTimeValue = DateTimeOffset.Now }, new DependentRow { FakeDependentEntityId = 457, DependentIntegerValue = 1, DependentTimeValue = DateTimeOffset.Now }, new DependentRow { FakeDependentEntityId = 458, DependentIntegerValue = 3, DependentTimeValue = DateTimeOffset.MaxValue } }; var actual = target.Load(dependentRows); Assert.AreEqual(dependentRows.Count, actual.Rows.Count); for (int i = 0; i < dependentRows.Count; i++) { var actualRow = new DependentRow { FakeDependentEntityId = (int)actual.Rows[i][nameof(DependentRow.FakeDependentEntityId)], DependentIntegerValue = (int)actual.Rows[i][nameof(DependentRow.DependentIntegerValue)], DependentTimeValue = (DateTimeOffset)actual.Rows[i][nameof(DependentRow.DependentTimeValue)] }; Assert.AreEqual(dependentRows.ElementAt(i), actualRow); } }
/// <summary> /// Register a dependency for this row. /// </summary> public void AddChild(DependentRow childRow) { this.ChildRows.Add(childRow); childRow.ParentRows.Add(this); }
public DbImportTool Import(ISimpleTaskHost host, DataSet data, DbConnection connection, DbTransaction transaction) { // Collections of actions: var toImport = new Queue<DependentRow>(); var toImportPerTable = new Dictionary<string, List<DependentRow>>(); var toUpdate = new Queue<DependentUpdate>(); var sqlUpdateCmds = new Dictionary<string, DbCommand>(); sqlUpdateCmds["IDENTITY"] = connection.CreateCommand("SELECT @@IDENTITY", CommandType.Text, transaction); // Change identity column values to negative to avoid conflicts on destination database: foreach (DataTable table in data.Tables) { foreach (DataColumn col in table.Columns) { if (col.AutoIncrement) { col.ReadOnly = false; foreach (DataRow row in table.Rows) { row[col] = -(int)row[col]; } } } } // Read all rows: foreach (DataTable table in data.Tables) { var perTable = toImportPerTable[table.TableName] = new List<DependentRow>(); foreach (DataRow row in table.Rows) { var drow = new DependentRow() { Row = row }; toImport.Enqueue(drow); perTable.Add(drow); } } host.Out.WriteLine("Importing {0} data rows...", toImport.Count); // Connect row dependencies: foreach (DataRelation relation in data.Relations) { // TODO: Should also include rows with non-AutoIncrement Primary Keys and multi-column Primary Keys. // Ignore relations where primary key is not an AutoIncrement field: if (relation.ParentColumns.Count() != 1 || !relation.ParentColumns[0].AutoIncrement) continue; var parentColumn = relation.ParentColumns[0]; var childColumn = relation.ChildColumns[0]; if (childColumn.AllowDBNull) { // If foreign key is nullable, make it null and register a delayed update: foreach (var parentRow in toImportPerTable[relation.ParentTable.TableName]) { var parentPkValue = parentRow.Row[parentColumn]; foreach (var childRow in toImportPerTable[relation.ChildTable.TableName].Where(dr => Object.Equals(dr.Row[childColumn], parentPkValue))) { toUpdate.Enqueue(new DependentUpdate() { Row = childRow.Row, Column = childColumn, SourceRow = parentRow.Row, SourceColumn = parentColumn }); childRow.Row[childColumn] = DBNull.Value; } } } else { // If foreign key row is not nullable, register dependency: foreach (var parentRow in toImportPerTable[relation.ParentTable.TableName]) { var parentPkValue = parentRow.Row[parentColumn]; foreach (var childRow in toImportPerTable[relation.ChildTable.TableName].Where(dr => Object.Equals(dr.Row[childColumn], parentPkValue))) { parentRow.AddChild(childRow); } } } } var totalActions = (double)(toImport.Count + toUpdate.Count); // Import rows: while (toImport.Count > 0) { var drow = toImport.Dequeue(); if (drow.HasAllDependenciesResolved) { drow.WriteToDatabase(host, connection, transaction, sqlUpdateCmds); drow.MarkResolved(); } else { //Console.WriteLine("SKIPPED : {0} ({1})", drow.Row.Table.TableName, String.Join(", ", drow.Values().Take(1).Select(v => (v ?? "##null").ToString()))); toImport.Enqueue(drow); } host.ReportProgress((totalActions - toImport.Count - toUpdate.Count) / totalActions, drow.Row.Table.TableName); } // Dispose commands: sqlUpdateCmds.Values.ToList().ForEach(cmd => cmd.Dispose()); host.Out.WriteLine("\r\nUpdating {0} data rows...", toUpdate.Count); // Perform delayed updates: using(var cmd = connection.CreateCommand()) { cmd.Transaction = transaction; cmd.AddParameter("@SourceValue", null); cmd.AddParameter("@PkValue", null); while (toUpdate.Count > 0) { var dupdate = toUpdate.Dequeue(); dupdate.WriteToDatabase(host, connection, cmd); host.ReportProgress((totalActions - toImport.Count - toUpdate.Count) / totalActions, dupdate.Row.Table.TableName); } } host.Out.WriteLine(); return this; }
public DbImportTool Import(ISimpleTaskHost host, DataSet data, DbConnection connection, DbTransaction transaction) { // Collections of actions: var toImport = new Queue <DependentRow>(); var toImportPerTable = new Dictionary <string, List <DependentRow> >(); var toUpdate = new Queue <DependentUpdate>(); var sqlUpdateCmds = new Dictionary <string, DbCommand>(); sqlUpdateCmds["IDENTITY"] = connection.CreateCommand("SELECT @@IDENTITY", CommandType.Text, transaction); // Change identity column values to negative to avoid conflicts on destination database: foreach (DataTable table in data.Tables) { foreach (DataColumn col in table.Columns) { if (col.AutoIncrement) { col.ReadOnly = false; foreach (DataRow row in table.Rows) { row[col] = -(int)row[col]; } } } } // Read all rows: foreach (DataTable table in data.Tables) { var perTable = toImportPerTable[table.TableName] = new List <DependentRow>(); foreach (DataRow row in table.Rows) { var drow = new DependentRow() { Row = row }; toImport.Enqueue(drow); perTable.Add(drow); } } host.Out.WriteLine("Importing {0} data rows...", toImport.Count); // Connect row dependencies: foreach (DataRelation relation in data.Relations) { // TODO: Should also include rows with non-AutoIncrement Primary Keys and multi-column Primary Keys. // Ignore relations where primary key is not an AutoIncrement field: if (relation.ParentColumns.Count() != 1 || !relation.ParentColumns[0].AutoIncrement) { continue; } var parentColumn = relation.ParentColumns[0]; var childColumn = relation.ChildColumns[0]; if (childColumn.AllowDBNull) { // If foreign key is nullable, make it null and register a delayed update: foreach (var parentRow in toImportPerTable[relation.ParentTable.TableName]) { var parentPkValue = parentRow.Row[parentColumn]; foreach (var childRow in toImportPerTable[relation.ChildTable.TableName].Where(dr => Object.Equals(dr.Row[childColumn], parentPkValue))) { toUpdate.Enqueue(new DependentUpdate() { Row = childRow.Row, Column = childColumn, SourceRow = parentRow.Row, SourceColumn = parentColumn }); childRow.Row[childColumn] = DBNull.Value; } } } else { // If foreign key row is not nullable, register dependency: foreach (var parentRow in toImportPerTable[relation.ParentTable.TableName]) { var parentPkValue = parentRow.Row[parentColumn]; foreach (var childRow in toImportPerTable[relation.ChildTable.TableName].Where(dr => Object.Equals(dr.Row[childColumn], parentPkValue))) { parentRow.AddChild(childRow); } } } } var totalActions = (double)(toImport.Count + toUpdate.Count); // Import rows: while (toImport.Count > 0) { var drow = toImport.Dequeue(); if (drow.HasAllDependenciesResolved) { drow.WriteToDatabase(host, connection, transaction, sqlUpdateCmds); drow.MarkResolved(); } else { //Console.WriteLine("SKIPPED : {0} ({1})", drow.Row.Table.TableName, String.Join(", ", drow.Values().Take(1).Select(v => (v ?? "##null").ToString()))); toImport.Enqueue(drow); } host.ReportProgress((totalActions - toImport.Count - toUpdate.Count) / totalActions, drow.Row.Table.TableName); } // Dispose commands: sqlUpdateCmds.Values.ToList().ForEach(cmd => cmd.Dispose()); host.Out.WriteLine("\r\nUpdating {0} data rows...", toUpdate.Count); // Perform delayed updates: using (var cmd = connection.CreateCommand()) { cmd.Transaction = transaction; cmd.AddParameter("@SourceValue", null); cmd.AddParameter("@PkValue", null); while (toUpdate.Count > 0) { var dupdate = toUpdate.Dequeue(); dupdate.WriteToDatabase(host, connection, cmd); host.ReportProgress((totalActions - toImport.Count - toUpdate.Count) / totalActions, dupdate.Row.Table.TableName); } } host.Out.WriteLine(); return(this); }