Operações assíncronas do Entity Framework 6 e TranscationScope
Pesquisei no stackoverflow, mas não consegui encontrar uma pergunta semelhante, aponte-me se já houver uma.
Eu estava tentando implementar um repositório reutilizável genérico com operações de sincronização e assíncrona, mas com meu pouco conhecimento sobre o Entity Framework e a Unidade de trabalho, estou lutando para encontrar a maneira correta de implementá-lo.
Eu adicionei algumas variações na operação SaveAndCommit, mas não sei qual é a melhor maneira de fazer isso com transação e assíncrona.
----Editar----
De acordo com meu entendimento, as transações devem ser usadas quando mais de uma operação é executada, mas, para fins de entendimento, eu a usei para uma operação. (Por favor me corrija se eu estiver errado)
Isto é o que eu fiz até agora
public class Service<TEntity> : IService<TEntity>
where TEntity : Entity
{
#region Constructor and Properties
UnitOfWork _unitOfWork { get { return UnitOfWork.UnitOfWorkPerHttpRequest; } }
protected DbSet<TEntity> Entities
{
get { return _unitOfWork.Set<TEntity>(); }
}
#endregion Constructor and Properties
#region Operations
public virtual IQueryable<TEntity> QueryableEntities()
{
return Entities;
}
public virtual async Task<IList<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> predicate)
{
return await Entities.Where(predicate).ToListAsync();
}
public virtual IList<TEntity> Where(Expression<Func<TEntity, bool>> predicate)
{
return Entities.Where(predicate).ToList();
}
public virtual async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
{
return await Entities.FirstOrDefaultAsync(predicate);
}
public virtual TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return Entities.FirstOrDefault(predicate);
}
public virtual async Task<TEntity> GetByIdAsync(int id)
{
return await Entities.FindAsync(id);
}
public virtual TEntity GetById(int id)
{
return Entities.Find(id);
}
// Method to the change the EntityState
public virtual void Save(TEntity entity)
{
if (entity.Id == 0)
{
Entities.Add(entity);
}
else
{
_unitOfWork.Entry(entity).State = EntityState.Modified;
}
}
#region Need clarification here
// Uses transaction scope to commit the entity and dispose automatically
// call rollback but this is not async and don't have any async
// functions (Or I could not find)
public virtual void SaveAndCommit(TEntity entity)
{
using (var transaction = _unitOfWork.BeginTransaction())
{
try
{
Save(entity);
transaction.Commit();
}
catch (DbEntityValidationException e)
{
}
}
}
// This is asynchronous but don't uses transaction
public virtual async Task SaveAndCommitAsync(TEntity entity)
{
try
{
Save(entity);
await _unitOfWork.SaveChangesAsync();
}
catch (DbEntityValidationException e)
{
}
}
// Tried to mix async and transaction but don't know if it will actually
// work or correct way of doing this
public virtual async Task SaveAndCommitWithTransactionAsync(TEntity entity)
{
using (var transaction = _unitOfWork.BeginTransaction())
{
try
{
Save(entity);
await _unitOfWork.SaveChangesAsync();
}
catch (DbEntityValidationException e)
{
transaction.Rollback();
}
}
}
#endregion Need clarification here
public virtual async Task DeleteAsync(TEntity entity)
{
if (entity == null) return;
Entities.Remove(entity);
await _unitOfWork.SaveChangesAsync();
}
//All similar methods for delete as for Save
public virtual async Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate = null)
{
if (predicate != null)
{
return await Entities.CountAsync(predicate);
}
return await Entities.CountAsync();
}
#endregion Operations
}
Por favor, me guie e sugira a melhor maneira de conseguir isso.
Agora parece que a maneira correta de implementar um escopo de transação com chamada assíncrona seria
public virtual async Task SaveAndCommitWithTransactionAsync(TEntity entity)
{
using (var transaction = _unitOfWork.BeginTransaction())
{
Save(entity);
await _unitOfWork.SaveChangesAsync();
// Still no changes made to database
transaction.Commit();
//Rollback will automatically be called by using in dispose method
}
}
ReferênciasReferência do MSDN
visualstudiomagazine.com Para: quando você chama SaveChanges, nenhuma das suas alterações entra em vigor até você chamar o método de Confirmação do objeto Transaction