Integridad de transacciones en el núcleo ASP.NET con marco de entidades y repositorio genérico -- # campo con entity-framework campo con repository campo con transactions camp codereview Relacionados El problema

Transaction integrity in asp.net core with entity framework and generic repository


1
vote

problema

Español

No tengo mucha experiencia en el marco de la entidad, anteriormente usé ADO.NET y DAPPER para la persistencia de datos. Por ahora, solo leí Microsoft Docs y vi algunos tutoriales de video. Intenté apegarme a consejos bien aceptados y haber construido una infraestructura de repositorio genérico con la ayuda de aquí y allá.

IENTITY

  public interface IEntity {     object Id { get; set; }      string CreatedBy { get; set; }      DateTime CreatedOn { get; set; }      string ModifiedBy { get; set; }      DateTime? ModifiedOn { get; set; } }  public interface IEntity<T> : IEntity {     new T Id { get; set; } }   

Baseentity

  public abstract class BaseEntity<T> : IEntity<T> {     [Key]     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]     public T Id { get; set; }      object IEntity.Id { get { return Id; } set { } }      public string CreatedBy { get; set; }      private DateTime? createdOn;     [DataType(DataType.DateTime)]     public DateTime CreatedOn     {         get { return createdOn ?? DateTime.UtcNow; }         set { createdOn = value; }     }      public string ModifiedBy { get; set; }      [DataType(DataType.DateTime)]     public DateTime? ModifiedOn { get; set; } }   

Entidad del usuario

  public class User : BaseEntity<int> {     public string FullName { get; set; }     public string Email { get; set; }     public UserType UserType { get; set; }     public string Password { get; set; }      public virtual ICollection<Comment> Comments { get; set; }     public virtual ICollection<Post> Posts { get; set; } }   

IREPOSITORIO

  public interface IRepository<TEntity> where TEntity: IEntity {     IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,                       string includeProperties = null,                       int? skip = null,                       int? take = null);      TEntity GetFirst(Expression<Func<TEntity, bool>> filter = null,                      Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,                      string includeProperties = null);      TEntity GetById(object id);      TEntity GetOne(Expression<Func<TEntity, bool>> filter = null,                    string includeProperties = null);      void Create(TEntity entity, string createdBy = null);      void Update(TEntity entity, string modifiedBy = null);      void Delete(TEntity entity);      void Delete(object id);      void Save(); }   

EFRepository

  public class EFRepository<TEntity> : IRepository<TEntity>     where TEntity : class, IEntity {     private DbContext _context;      public EFRepository(BlogContext context)     {         _context = context;     }      protected virtual IEnumerable<TEntity> GetQueryable(     Expression<Func<TEntity, bool>> filter = null,     Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,     string includeProperties = null,     int? skip = null,     int? take = null)     {         includeProperties = includeProperties ?? string.Empty;         IQueryable<TEntity> query = _context.Set<TEntity>();          if (filter != null)         {             query = query.Where(filter);         }          foreach (var includeProperty in includeProperties.Split             (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))         {             query = query.Include(includeProperty);         }          if (orderBy != null)         {             query = orderBy(query);         }          if (skip.HasValue)         {             query = query.Skip(skip.Value);         }          if (take.HasValue)         {             query = query.Take(take.Value);         }          return query.AsEnumerable();     }      public IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = null, int? skip = null, int? take = null)     {         return GetQueryable(orderBy: orderBy, includeProperties: includeProperties, skip: skip, take: take);     }      public TEntity GetById(object id)     {         return _context.Set<TEntity>().Find(id);     }      public TEntity GetFirst(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = null)     {         return GetQueryable(filter: filter, orderBy: orderBy, includeProperties: includeProperties).FirstOrDefault();     }      public TEntity GetOne(Expression<Func<TEntity, bool>> filter = null, string includeProperties = null)     {         return GetQueryable(filter: filter, includeProperties: includeProperties).SingleOrDefault();     }      public void Save()     {         try         {             _context.SaveChanges();         }         catch (Exception e)         {         }     }      public void Create(TEntity entity, string createdBy = null)     {         entity.CreatedOn = DateTime.UtcNow;         entity.CreatedBy = createdBy;         _context.Add<TEntity>(entity);     }      public void Update(TEntity entity, string modifiedBy = null)     {         entity.CreatedOn = DateTime.UtcNow;         entity.CreatedBy = modifiedBy;         _context.Set<TEntity>().Attach(entity);         _context.Entry(entity).State = EntityState.Modified;     }      public void Delete(TEntity entity)     {         var dbSet = _context.Set<TEntity>();          if (_context.Entry(entity).State == EntityState.Detached)             dbSet.Attach(entity);          dbSet.Remove(entity);     }      public void Delete(object id)     {         TEntity entity = _context.Set<TEntity>().Find(id);         Delete(entity);     } }   

Iservice

  public interface IService {     IRepository<T> GetRepository<T>(DbContext context) where T : class, IEntity; }   

Baseservice

  public abstract class BaseService : IService {     public BaseService(BlogContext context, ILogger<BaseService> logger)     {         _context = context;         _logger = logger;     }      protected DbContext _context { get; set; }      protected readonly ILogger<BaseService> _logger;      public IRepository<T> GetRepository<T>(DbContext context) where T : class, IEntity     {         return new EFRepository<T>((BlogContext)context);     }     public IRepository<T> GetRepository<T>() where T : class, IEntity     {         return GetRepository<T>(_context);     } }   

IUSERSERVICE

  public interface IAuthorService {     bool DeleteAuthorWithEntireStuff(int userId); }   

UserService

  public class UserService : BaseService, IAuthorService {     public UserService(BlogContext context, ILogger<UserService> logger) : base(context, logger) { }      public bool DeleteAuthorWithEntireStuff(int id)     {         try         {             var userRepo = GetRepository<User>();             var commentRepo = GetRepository<Comment>();             var postRepo = GetRepository<Post>();              var user = userRepo.GetAll().Where(u => u.Id == id).FirstOrDefault();              if (user != null)             {                 var commentList = commentRepo.GetAll().Where(c => c.UserId == id).ToList();                 var postList = postRepo.GetAll().Where(p => p.AuthorId == id).ToList();                  foreach (var item in commentList)                     commentRepo.Delete(item);                  foreach (var item in postList)                     postRepo.Delete(item);                  userRepo.Delete(user);                  _context.SaveChanges();             }              return true;         }         catch (Exception)         {             throw;         }     } }   

y finalmente el controlador

  public class UserController : Controller {     private readonly IRepository<User> _repository;     private readonly IUserService _authorService;      public UserController(IRepository<User> repository, IUserService authorService)     {         _repository = repository;         _authorService = authorService;     }      [HttpPost]     public IActionResult Create([FromBody]User model)     {         try         {             _repository.Create(model);             _repository.Save();             return Ok(model);         }         catch(Exception ex)         {             return BadRequest(ex);         }      }     [HttpPost]     [Route("DeletUserEntirely")]     public IActionResult DeleteUserEntirely([FromBody]User model)     {         try         {             if (_authorService.DeleteUserEntirely(model.Id))                 return Ok();             else                 return BadRequest();         }         catch (Exception ex)         {             return BadRequest(ex);         }      } }   

Como se ve en el código de usuario de los usuarios cuando necesito ejecutar varios comandos en una transacción, hago uso de unidad de trabajo de EF ( public abstract class BaseEntity<T> : IEntity<T> { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public T Id { get; set; } object IEntity.Id { get { return Id; } set { } } public string CreatedBy { get; set; } private DateTime? createdOn; [DataType(DataType.DateTime)] public DateTime CreatedOn { get { return createdOn ?? DateTime.UtcNow; } set { createdOn = value; } } public string ModifiedBy { get; set; } [DataType(DataType.DateTime)] public DateTime? ModifiedOn { get; set; } } 0 ).

No creé ninguna unidad adicional de clases de trabajo como se sugiere en pocos lugares o envuelve mis reposs en el alcance de la transacción. Como se discutió aquí , algunas personas defienden la unidad de implementaciones de trabajo para la integridad de las transacciones que yo No lo entiendo por qué, mientras que la EF implementa el patrón UOW ya.

No he probado tanto el código anterior, pero hasta ahora parece estar bien.

BTW, usé Chris Pratt's repositorio genérico enfoque. ¿Algún problema con este enfoque, especialmente con la perspectiva de las transacciones en el marco de entidades de uso de repositorio genérico?

Original en ingles

I am not very experienced in Entity Framework, I previously used ADO.Net and Dapper for data persistence. For now, I only read Microsoft docs and watched a few video tutorials. I tried to stick to well accepted advice and have built a generic repository infrastructure with the help of from here and there.

IEntity

public interface IEntity {     object Id { get; set; }      string CreatedBy { get; set; }      DateTime CreatedOn { get; set; }      string ModifiedBy { get; set; }      DateTime? ModifiedOn { get; set; } }  public interface IEntity<T> : IEntity {     new T Id { get; set; } } 

BaseEntity

public abstract class BaseEntity<T> : IEntity<T> {     [Key]     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]     public T Id { get; set; }      object IEntity.Id { get { return Id; } set { } }      public string CreatedBy { get; set; }      private DateTime? createdOn;     [DataType(DataType.DateTime)]     public DateTime CreatedOn     {         get { return createdOn ?? DateTime.UtcNow; }         set { createdOn = value; }     }      public string ModifiedBy { get; set; }      [DataType(DataType.DateTime)]     public DateTime? ModifiedOn { get; set; } } 

User Entity

public class User : BaseEntity<int> {     public string FullName { get; set; }     public string Email { get; set; }     public UserType UserType { get; set; }     public string Password { get; set; }      public virtual ICollection<Comment> Comments { get; set; }     public virtual ICollection<Post> Posts { get; set; } } 

IRepository

public interface IRepository<TEntity> where TEntity: IEntity {     IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,                       string includeProperties = null,                       int? skip = null,                       int? take = null);      TEntity GetFirst(Expression<Func<TEntity, bool>> filter = null,                      Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,                      string includeProperties = null);      TEntity GetById(object id);      TEntity GetOne(Expression<Func<TEntity, bool>> filter = null,                    string includeProperties = null);      void Create(TEntity entity, string createdBy = null);      void Update(TEntity entity, string modifiedBy = null);      void Delete(TEntity entity);      void Delete(object id);      void Save(); } 

EFRepository

public class EFRepository<TEntity> : IRepository<TEntity>     where TEntity : class, IEntity {     private DbContext _context;      public EFRepository(BlogContext context)     {         _context = context;     }      protected virtual IEnumerable<TEntity> GetQueryable(     Expression<Func<TEntity, bool>> filter = null,     Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,     string includeProperties = null,     int? skip = null,     int? take = null)     {         includeProperties = includeProperties ?? string.Empty;         IQueryable<TEntity> query = _context.Set<TEntity>();          if (filter != null)         {             query = query.Where(filter);         }          foreach (var includeProperty in includeProperties.Split             (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))         {             query = query.Include(includeProperty);         }          if (orderBy != null)         {             query = orderBy(query);         }          if (skip.HasValue)         {             query = query.Skip(skip.Value);         }          if (take.HasValue)         {             query = query.Take(take.Value);         }          return query.AsEnumerable();     }      public IEnumerable<TEntity> GetAll(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = null, int? skip = null, int? take = null)     {         return GetQueryable(orderBy: orderBy, includeProperties: includeProperties, skip: skip, take: take);     }      public TEntity GetById(object id)     {         return _context.Set<TEntity>().Find(id);     }      public TEntity GetFirst(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = null)     {         return GetQueryable(filter: filter, orderBy: orderBy, includeProperties: includeProperties).FirstOrDefault();     }      public TEntity GetOne(Expression<Func<TEntity, bool>> filter = null, string includeProperties = null)     {         return GetQueryable(filter: filter, includeProperties: includeProperties).SingleOrDefault();     }      public void Save()     {         try         {             _context.SaveChanges();         }         catch (Exception e)         {         }     }      public void Create(TEntity entity, string createdBy = null)     {         entity.CreatedOn = DateTime.UtcNow;         entity.CreatedBy = createdBy;         _context.Add<TEntity>(entity);     }      public void Update(TEntity entity, string modifiedBy = null)     {         entity.CreatedOn = DateTime.UtcNow;         entity.CreatedBy = modifiedBy;         _context.Set<TEntity>().Attach(entity);         _context.Entry(entity).State = EntityState.Modified;     }      public void Delete(TEntity entity)     {         var dbSet = _context.Set<TEntity>();          if (_context.Entry(entity).State == EntityState.Detached)             dbSet.Attach(entity);          dbSet.Remove(entity);     }      public void Delete(object id)     {         TEntity entity = _context.Set<TEntity>().Find(id);         Delete(entity);     } } 

IService

public interface IService {     IRepository<T> GetRepository<T>(DbContext context) where T : class, IEntity; } 

BaseService

public abstract class BaseService : IService {     public BaseService(BlogContext context, ILogger<BaseService> logger)     {         _context = context;         _logger = logger;     }      protected DbContext _context { get; set; }      protected readonly ILogger<BaseService> _logger;      public IRepository<T> GetRepository<T>(DbContext context) where T : class, IEntity     {         return new EFRepository<T>((BlogContext)context);     }     public IRepository<T> GetRepository<T>() where T : class, IEntity     {         return GetRepository<T>(_context);     } } 

IUserService

public interface IAuthorService {     bool DeleteAuthorWithEntireStuff(int userId); } 

UserService

public class UserService : BaseService, IAuthorService {     public UserService(BlogContext context, ILogger<UserService> logger) : base(context, logger) { }      public bool DeleteAuthorWithEntireStuff(int id)     {         try         {             var userRepo = GetRepository<User>();             var commentRepo = GetRepository<Comment>();             var postRepo = GetRepository<Post>();              var user = userRepo.GetAll().Where(u => u.Id == id).FirstOrDefault();              if (user != null)             {                 var commentList = commentRepo.GetAll().Where(c => c.UserId == id).ToList();                 var postList = postRepo.GetAll().Where(p => p.AuthorId == id).ToList();                  foreach (var item in commentList)                     commentRepo.Delete(item);                  foreach (var item in postList)                     postRepo.Delete(item);                  userRepo.Delete(user);                  _context.SaveChanges();             }              return true;         }         catch (Exception)         {             throw;         }     } } 

And finally controller

public class UserController : Controller {     private readonly IRepository<User> _repository;     private readonly IUserService _authorService;      public UserController(IRepository<User> repository, IUserService authorService)     {         _repository = repository;         _authorService = authorService;     }      [HttpPost]     public IActionResult Create([FromBody]User model)     {         try         {             _repository.Create(model);             _repository.Save();             return Ok(model);         }         catch(Exception ex)         {             return BadRequest(ex);         }      }     [HttpPost]     [Route("DeletUserEntirely")]     public IActionResult DeleteUserEntirely([FromBody]User model)     {         try         {             if (_authorService.DeleteUserEntirely(model.Id))                 return Ok();             else                 return BadRequest();         }         catch (Exception ex)         {             return BadRequest(ex);         }      } } 

As you see in the UserService code when I need to run multiple commands in one transaction, I make use of the ef's unit of work (_context.SaveChanges()).

I did not create any extra unit of work classes as suggested at few places or wrap my repos in transaction scope. As discussed here, some people defend unit of work implementations for transaction integrity that I do not still get it why while ef implementing uow pattern already.

I haven't tested above code so much but till now it seems ok.

Btw, I used Chris Pratt's Generic Repository approach. Any problems with this approach, especially with the perspective of transactions in generic repository use entity framework?

           
     
     

Lista de respuestas


Relacionados problema

4  Método de capa de acceso a datos con manejo de transacciones  ( Data access layer method with transaction handling ) 
Solo quiero saber si he hecho la transacción que maneja bien. Además, ¿qué pasa con los otros tipos de transacciones disponibles en .NET con respecto a este c...

1  Transacción bancaria segura de hilo: depósito, retiro, saldo de verificación y transferencia en Java  ( Thread safe bank transaction deposit withdrawal check balance and transfer in ) 
He hecho una clase, que es un depósito de apoyo a la implementación de la implementación segura de hilo, retiro, verifique la consulta de saldo y la transfere...

1  Pila transaccional  ( Transactional stack ) 
Se trata de la pila de números, que puede tener transacción. si comienzas Transacción, debe comprometerlo para agregar números en realidad apilar. ...

1  Integridad de transacciones en el núcleo ASP.NET con marco de entidades y repositorio genérico  ( Transaction integrity in asp net core with entity framework and generic reposito ) 
No tengo mucha experiencia en el marco de la entidad, anteriormente usé ADO.NET y DAPPER para la persistencia de datos. Por ahora, solo leí Microsoft Docs y v...

3  Eliminar millones de registros en lotes  ( Deleting millions of logs in batches ) 
Tengo una mesa de crecimiento rápido con troncos que con frecuencia tengo que eliminar (el servidor no tiene muchos recursos). Crece por al menos dos millones...

4  Marco SWIFT que facilita hacer cambios atómicos a varios objetos a la vez  ( Swift framework that facilitates making atomic changes to several objects at a t ) 
Para los propósitos de una aplicación en la que trabajo, he creado un marco separado que abstrae el mecanismo de hacer cambios atómicos a las estructuras de o...

7  Sincronización del procesamiento de transacciones  ( Synchronization of transaction processing ) 
Hay un servidor que hace lo siguiente: Recibir solicitud con ID de transacción carga la transacción correspondiente del almacenamiento. Nuevo objeto de t...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos