Suis-je utiliser correctement l'unité de travail ici? (Framework 4 Entityi POCO)
-
25-09-2019 - |
Question
J'ai trouvé quelques exemples de la façon de créer l'unité de travail avec EF4, je n'ai pas utilisé di / cio et je voudrais garder les choses simples et cela un exemple (90% d'inspiration) et je pense qu'il est ok, mais depuis que je je regarde un modèle à utiliser à partir de maintenant je voudrais demander un avis, une dernière fois.
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();
}
}
Et enfin
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;
}
}
}
}
}
Après s'être débarrassé si le IUnitOfWork et IDisposal l'CreateUser ressemble à ceci:
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;
}
}
}
}
La solution
Cela ressemble fondamentalement OK. Quelques suggestions cependant:
- Vous ne devriez pas laisser le dépôt disposer les
TemplateEntities
. La raison en est que lorsque vous avez besoin de deux dépôts dans une transaction, vous avez un problème. Vous devez déplacer la responsabilité de disposer duTemplateEntities
au même niveau que leTransactionScope
; - Le
TransactionScope
doit être déplacé à un niveau supérieur. De préférence, leTemplateEntities
doit être instancié dans unTransactionScope
; - Vous ne devez pas créer l'emballage de
Save
si elle ne contient pas de fonctionnalité. Si vous spécifiez levoid SaveChanges()
sur l'interfaceIUnitOfWork
, cela va prendre leSaveChanges
duTemplateEntities
; - Personnellement, je n'aurais pas
string GetUserNameByEmail(...)
maisUser GetUserByEmail(...)
car alors cela aussi servir votre but et vous avez l'avantage de ne pas avoir deux méthodes qui recherche par adresse e-mail lorsque vous avez besoin plus tard, leUser GetUserByEmail(...)
; - Vous voudrez peut-être penser à faire
ctx
privé, ou au moins un setter privé commepublic TemplateEntities Ctx { get; private set; }
; - Vous pouvez créer un référentiel abstrait avec des méthodes comme l'exemple ci-dessous. Cela vous fera économiser beaucoup de dactylographie terne à long terme:
-
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();
}
/* ... */
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow