Estoy usando correctamente unidad de trabajo aquí? (Entityi Framework 4 POCO)
-
25-09-2019 - |
Pregunta
He encontrado algunos ejemplos de cómo crear unidad de trabajo con EF4, no he utilizado di / COI y me gustaría mantener las cosas simples y esto un ejemplo (90% de inspiración) y creo que está bien, pero desde que Busco a un patrón de uso a partir de ahora me gustaría pedir un dictamen por última vez.
public interface IUnitOfWork
{
void Save();
}
public partial class TemplateEntities : ObjectContext, IUnitOfWork
{
....
public void Save()
{
SaveChanges();
}
}
public interface IUserRepository
{
User GetUser(string username);
string GetUserNameByEmail(string email);
void AddUser(User userToAdd);
void UpdateUser(User userToUpdate);
void DeleteUser(User userToDelete);
//some other
}
public class UserRepository : IUserRepository, IDisposable
{
public TemplateEntities ctx;
public UserRepository(IUnitOfWork unit)
{
ctx = unit as TemplateEntities;
}
public User GetUser(string username)
{
return (from u in ctx.Users
where u.UserName == username
select u).SingleOrDefault();
}
public string GetUserNameByEmail(string email)
{
return (from u in ctx.Users
where u.Email == email
select u.UserName).SingleOrDefault();
}
public void AddUser(User userToAdd)
{
ctx.Users.AddObject(userToAdd);
}
public void UpdateUser(User userToUpdate)
{
ctx.Users.Attach(userToUpdate);
ctx.ObjectStateManager.ChangeObjectState(userToUpdate, System.Data.EntityState.Modified);
}
public void DeleteUser(User userToDelete)
{
ctx.Users.Attach(userToDelete);
ctx.ObjectStateManager.ChangeObjectState(userToDelete, System.Data.EntityState.Deleted);
}
public void Dispose()
{
if (ctx != null)
ctx.Dispose();
}
}
Y, por último
public class BogusMembership : MembershipProvider
{
public MembershipCreateStatus CreateUser(string username, string password, string email, bool autoemail, string fullname)
{
IUnitOfWork ctx = new TemplateEntities();
using (UserRepository rep = new UserRepository(ctx))
{
using (TransactionScope tran = new TransactionScope())
{
if (rep.GetUser(username) != null)
return MembershipCreateStatus.DuplicateUserName;
if (requiresUniqueEmail && !String.IsNullOrEmpty(rep.GetUserNameByEmail(email)))
return MembershipCreateStatus.DuplicateEmail;
User userToCreate = new User
{
UserName = username,
PassWord = EncodePassword(password),
FullName = fullname,
Email = email,
AutoEmail = autoemail
};
try
{
rep.AddUser(userToCreate);
ctx.Save();
tran.Complete();
return MembershipCreateStatus.Success;
}
catch
{
return MembershipCreateStatus.UserRejected;
}
}
}
}
}
Después de deshacerse si el IUnitOfWork y IDisposal las miradas CreateUser como esta:
public MembershipCreateStatus CreateUser(string username, string password, string email, bool autoemail, string fullname)
{
using (TransactionScope tran = new TransactionScope())
{
using (TemplateEntities ctx = new TemplateEntities())
{
UserRepository rep = new UserRepository(ctx);
//OtherRepository rep2 = new OtherRepository(ctx);
if (rep.GetUser(username) != null)
return MembershipCreateStatus.DuplicateUserName;
if (requiresUniqueEmail && !String.IsNullOrEmpty(rep.GetUserNameByEmail(email)))
return MembershipCreateStatus.DuplicateEmail;
User userToCreate = new User
{
UserName = username,
PassWord = EncodePassword(password),
FullName = fullname,
Email = email,
AutoEmail = autoemail
};
try
{
rep.AddUser(userToCreate);
ctx.SaveChanges();
tran.Complete();
return MembershipCreateStatus.Success;
}
catch
{
return MembershipCreateStatus.UserRejected;
}
}
}
}
Solución
Esto parece básicamente bien. A pesar de algunas sugerencias:
- No se debe dejar que el repositorio de disponer la
TemplateEntities
. La razón de esto es que cuando se necesita dos centros de almacenamiento dentro de una transacción, usted tiene un problema. Debe moverse la responsabilidad de disponer elTemplateEntities
al mismo nivel que elTransactionScope
; - El
TransactionScope
debe ser trasladado a un nivel más alto. Preferiblemente, elTemplateEntities
debe ser instanciado dentro de unTransactionScope
; - Usted no tiene que crear el envoltorio
Save
si no contiene funcionalidad. Si especifica elvoid SaveChanges()
en la interfazIUnitOfWork
, esto va a recoger elSaveChanges
delTemplateEntities
; - En lo personal no tendría
string GetUserNameByEmail(...)
sinoUser GetUserByEmail(...)
porque entonces esto también va a servir a su propósito y usted tiene la ventaja de no tener dos métodos esa búsqueda por e-mail cuando posteriormente se necesita elUser GetUserByEmail(...)
; - Es posible que desee pensar en hacer
ctx
privada, o por lo menos un regulador privado como lospublic TemplateEntities Ctx { get; private set; }
; - Se puede crear un repositorio abstracto con métodos como el ejemplo a continuación. Esto le ahorrará un montón de escribir aburrido en el largo plazo:
-
public interface IRepository<TEntity>
{
void Delete(TEntity entity);
/* ... */
}
public abstract class AbstractRepository<TEntity> : IRepository<TEntity>
{
public TemplateEntities ctx;
public AbstractRepository(IUnitOfWork unit)
{
ctx = unit as TemplateEntities;
}
protected abstract ObjectSet<TEntity> Entites { get; }
public virtual void Delete(TEntity entity)
{
Entities.Attach(entity);
ctx.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Deleted);
}
/* ... */
}
public interface IUserRepository : IRepository<User>
{
User GetUser(string username);
/* ... */
}
public class UserRepository : AbstractRepository<User>, IUserRepository
{
public UserRepository(IUnitOfWork unit)
: base(unit)
{
}
protected override ObjectSet<User> Entites
{
get { return ctx.Users; }
}
public User GetUser(string username)
{
return (from u in ctx.Users
where u.UserName == username
select u).SingleOrDefault();
}
/* ... */
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow