Skip to content

Commit

Permalink
Merge pull request #44 from borisermakof/#43_Add_BulkUpdate
Browse files Browse the repository at this point in the history
#43 Add BulkUpdate/BulkUpdateAsync
  • Loading branch information
borisermakof authored May 30, 2017
2 parents 4660031 + 9eeb72f commit b502088
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 5 deletions.
16 changes: 16 additions & 0 deletions src/MicroOrm.Dapper.Repositories/DapperRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,22 @@ public virtual async Task<int> BulkInsertAsync(IEnumerable<TEntity> instances, I
return count;
}

/// <inheritdoc />
public bool BulkUpdate(IEnumerable<TEntity> instances, IDbTransaction transaction = null)
{
var queryResult = SqlGenerator.GetBulkUpdate(instances);
var result = Connection.Execute(queryResult.GetSql(), queryResult.Param, transaction) > 0;
return result;
}

/// <inheritdoc />
public async Task<bool> BulkUpdateAsync(IEnumerable<TEntity> instances, IDbTransaction transaction = null)
{
var queryResult = SqlGenerator.GetBulkUpdate(instances);
var result = await Connection.ExecuteAsync(queryResult.GetSql(), queryResult.Param, transaction) > 0;
return result;
}

/// <inheritdoc />
public virtual bool Delete(TEntity instance, IDbTransaction transaction = null)
{
Expand Down
10 changes: 10 additions & 0 deletions src/MicroOrm.Dapper.Repositories/IDapperRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,16 @@ Task<IEnumerable<TEntity>> FindAllAsync<TChild1, TChild2, TChild3, TChild4, TChi
/// </summary>
bool Update(TEntity instance, IDbTransaction transaction = null);

/// <summary>
/// Bulk Update objects in DB
/// </summary>
Task<bool> BulkUpdateAsync(IEnumerable<TEntity> instances, IDbTransaction transaction = null);

/// <summary>
/// Bulk Update objects in DB
/// </summary>
bool BulkUpdate(IEnumerable<TEntity> instances, IDbTransaction transaction = null);

/// <summary>
/// Update object in DB
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public interface ISqlGenerator<TEntity> where TEntity : class
/// </summary>
SqlQuery GetUpdate(TEntity entity);

/// <summary>
/// Get SQL for bulk UPDATE Query
/// </summary>
SqlQuery GetBulkUpdate(IEnumerable<TEntity> entities);

/// <summary>
/// Get SQL for SELECT Query by Id
/// </summary>
Expand Down
47 changes: 42 additions & 5 deletions src/MicroOrm.Dapper.Repositories/SqlGenerator/SqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,7 @@ public virtual SqlQuery GetBulkInsert(IEnumerable<TEntity> entities)
if (!entitiesArray.Any())
throw new ArgumentException("collection is empty");

var arrayEntities = entitiesArray.ToArray();
var entityType = arrayEntities[0].GetType();
var entityType = entitiesArray[0].GetType();

var properties = (IsIdentity ? SqlProperties.Where(p => !p.PropertyName.Equals(IdentitySqlProperty.PropertyName, StringComparison.OrdinalIgnoreCase)) : SqlProperties).ToList();

Expand All @@ -229,13 +228,13 @@ public virtual SqlQuery GetBulkInsert(IEnumerable<TEntity> entities)
var values = new List<string>();
var parameters = new Dictionary<string, object>();

for (var i = 0; i < arrayEntities.Length; i++)
for (var i = 0; i < entitiesArray.Length; i++)
{
if (HasUpdatedAt)
UpdatedAtProperty.SetValue(arrayEntities[i], DateTime.UtcNow);
UpdatedAtProperty.SetValue(entitiesArray[i], DateTime.UtcNow);

foreach (var property in properties)
parameters.Add(property.PropertyName + i, entityType.GetProperty(property.PropertyName).GetValue(arrayEntities[i], null));
parameters.Add(property.PropertyName + i, entityType.GetProperty(property.PropertyName).GetValue(entitiesArray[i], null));

values.Add("(" + string.Join(", ", properties.Select(p => "@" + p.PropertyName + i)) + ")");
}
Expand Down Expand Up @@ -264,6 +263,44 @@ public virtual SqlQuery GetUpdate(TEntity entity)
return query;
}

/// <inheritdoc />
public virtual SqlQuery GetBulkUpdate(IEnumerable<TEntity> entities)
{
var entitiesArray = entities as TEntity[] ?? entities.ToArray();
if (!entitiesArray.Any())
throw new ArgumentException("collection is empty");

var entityType = entitiesArray[0].GetType();

var properties = SqlProperties.Where(p => !KeySqlProperties.Any(k => k.PropertyName.Equals(p.PropertyName, StringComparison.OrdinalIgnoreCase)) && !p.IgnoreUpdate);

var query = new SqlQuery();

var parameters = new Dictionary<string, object>();

for (var i = 0; i < entitiesArray.Length; i++)
{
if (HasUpdatedAt)
UpdatedAtProperty.SetValue(entitiesArray[i], DateTime.UtcNow);

query.SqlBuilder.Append(" UPDATE " + TableName + " SET " + string.Join(", ", properties.Select(p => p.ColumnName + " = @" + p.PropertyName + i)) + " WHERE " + string.Join(" AND ", KeySqlProperties.Select(p => p.ColumnName + " = @" + p.PropertyName + i)));

foreach (var property in properties)
{
parameters.Add(property.PropertyName + i, entityType.GetProperty(property.PropertyName).GetValue(entitiesArray[i], null));
}

foreach (var property in KeySqlProperties)
{
parameters.Add(property.PropertyName + i, entityType.GetProperty(property.PropertyName).GetValue(entitiesArray[i], null));
}
}

query.SetParam(parameters);

return query;
}

private SqlQuery AppendWhereQuery(SqlQuery sqlQuery, Expression<Func<TEntity, bool>> predicate)
{
IDictionary<string, object> dictionary = new Dictionary<string, object>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,5 +434,61 @@ public void Delete()

Assert.Equal(1, objectsCount);
}

[Fact]
public void BulkUpdate()
{
var phone1 = new Phone { Code = "Kiev123", Number = "Kiev123" };
var phone2 = new Phone { Code = "Kiev123", Number = "Kiev333" };

_sqlDatabaseFixture.Db.Phones.Insert(phone1);
_sqlDatabaseFixture.Db.Phones.Insert(phone2);

var insertedPhone1 = _sqlDatabaseFixture.Db.Phones.FindById(phone1.Id);
var insertedPhone2 = _sqlDatabaseFixture.Db.Phones.FindById(phone2.Id);
Assert.Equal("Kiev123", phone1.Number);
Assert.Equal("Kiev333", phone2.Number);

insertedPhone1.Number = "Kiev666";
insertedPhone2.Number = "Kiev777";

bool result = _sqlDatabaseFixture.Db.Phones.BulkUpdate(new List<Phone> { insertedPhone1, insertedPhone2 });

Assert.True(result);

var newPhone1 = _sqlDatabaseFixture.Db.Phones.FindById(phone1.Id);
var newPhone2 = _sqlDatabaseFixture.Db.Phones.FindById(phone2.Id);

Assert.Equal("Kiev666", newPhone1.Number);
Assert.Equal("Kiev777", newPhone2.Number);
}

[Fact]
public async void BulkUpdateAsync()
{
var phone1 = new Phone { Code = "MSK123", Number = "MSK123" };
var phone2 = new Phone { Code = "MSK123", Number = "MSK333" };

await _sqlDatabaseFixture.Db.Phones.InsertAsync(phone1);
await _sqlDatabaseFixture.Db.Phones.InsertAsync(phone2);

var insertedPhone1 = await _sqlDatabaseFixture.Db.Phones.FindByIdAsync(phone1.Id);
var insertedPhone2 = await _sqlDatabaseFixture.Db.Phones.FindByIdAsync(phone2.Id);
Assert.Equal("MSK123", phone1.Number);
Assert.Equal("MSK333", phone2.Number);

insertedPhone1.Number = "MSK666";
insertedPhone2.Number = "MSK777";

bool result = await _sqlDatabaseFixture.Db.Phones.BulkUpdateAsync(new List<Phone> { insertedPhone1, insertedPhone2 });

Assert.True(result);

var newPhone1 = await _sqlDatabaseFixture.Db.Phones.FindByIdAsync(phone1.Id);
var newPhone2 = await _sqlDatabaseFixture.Db.Phones.FindByIdAsync(phone2.Id);

Assert.Equal("MSK666", newPhone1.Number);
Assert.Equal("MSK777", newPhone2.Number);
}
}
}
32 changes: 32 additions & 0 deletions test/MicroOrm.Dapper.Repositories.Tests/Tests/SqlGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,5 +368,37 @@ public void MsSqlDeleteWithMultiplePredicate()

Assert.Equal("DELETE FROM [DAB].[Phones] WHERE [DAB].[Phones].[IsActive] = @IsActive AND [DAB].[Phones].[Number] = @Number", sqlQuery.GetSql());
}

[Fact]
public void MsSqlBulkUpdate()
{
ISqlGenerator<Phone> userSqlGenerator = new SqlGenerator<Phone>(ESqlConnector.MSSQL, true);
List<Phone> phones = new List<Phone>
{
new Phone { Id = 10, IsActive = true, Number = "111" },
new Phone { Id = 10, IsActive = false, Number = "222" }
};

var sqlQuery = userSqlGenerator.GetBulkUpdate(phones);

Assert.Equal(" UPDATE [DAB].[Phones] SET [Number] = @Number0, [IsActive] = @IsActive0 WHERE [Id] = @Id0" +
" UPDATE [DAB].[Phones] SET [Number] = @Number1, [IsActive] = @IsActive1 WHERE [Id] = @Id1", sqlQuery.GetSql());
}

[Fact]
public void MySqlBulkUpdate()
{
ISqlGenerator<Phone> userSqlGenerator = new SqlGenerator<Phone>(ESqlConnector.MySQL, true);
List<Phone> phones = new List<Phone>
{
new Phone { Id = 10, IsActive = true, Number = "111" },
new Phone { Id = 10, IsActive = false, Number = "222" }
};

var sqlQuery = userSqlGenerator.GetBulkUpdate(phones);

Assert.Equal(" UPDATE `DAB`.`Phones` SET `Number` = @Number0, `IsActive` = @IsActive0 WHERE `Id` = @Id0" +
" UPDATE `DAB`.`Phones` SET `Number` = @Number1, `IsActive` = @IsActive1 WHERE `Id` = @Id1", sqlQuery.GetSql());
}
}
}

0 comments on commit b502088

Please sign in to comment.