2010-10-24 10 views
9

Ho trovato alcuni esempi su come creare unità di lavoro con ef4, non ho usato di/ioc e vorrei mantenere le cose semplici e questo è un esempio (ispirato al 90%) e penso va bene ma visto che sto guardando uno schema da usare d'ora in poi vorrei chiedere un'opinione un'ultima volta.Sto usando correttamente l'Unità di lavoro qui? (Entityi Framework 4 POCO)

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(); 
    } 
} 

E infine

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; 
        } 
       } 
      } 
     } 
    } 

dopo essersi liberati se l'IUnitOfWork e IDisposal il CreateUser aspetto:

 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; 
        } 
       } 
      } 
     } 

risposta

2

questo sembra fondamentalmente OK. Alcuni suggerimenti però:

  • Non si deve lasciare che il repository smaltire il TemplateEntities. La ragione di ciò è che quando hai bisogno di due repository all'interno di una transazione, hai un problema. È necessario trasferire la responsabilità dello smaltimento dello TemplateEntities allo stesso livello di TransactionScope;
  • Il TransactionScope deve essere spostato su un livello superiore. Preferibilmente, il TemplateEntities deve essere istanziato all'interno di un TransactionScope;
  • Non è necessario creare il wrapper Save se non contiene funzionalità. Se si specifica void SaveChanges() nell'interfaccia IUnitOfWork, verrà prelevato il numero SaveChanges di TemplateEntities;
  • Personalmente non avrei string GetUserNameByEmail(...) ma piuttosto User GetUserByEmail(...) perché in questo modo servirò anche il tuo scopo e hai il vantaggio di non avere due metodi di ricerca per indirizzo e-mail quando in seguito ti servirà il User GetUserByEmail(...);
  • Si consiglia di pensare a rendere privato ctx o almeno un setter privato come public TemplateEntities Ctx { get; private set; };
  • È possibile creare un repository astratto con metodi come nell'esempio seguente. Questo vi farà risparmiare un sacco di battitura noiosa a lungo andare:

-

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(); 
    } 

    /* ... */ 
} 
+0

Pensi che dovrei liberarmi di interfaccia IUnitOfWork? – gigi

+0

Non lo so, forse. Non vedo il valore aggiunto con questa configurazione. Normalmente, devi aggiungere un ulteriore livello di astrazione quando ad es. avere due database che sono entrambi gestiti dall'unità di lavoro. Quindi il repository otterrebbe il suo contesto dall'unità di lavoro. Fondamentalmente, 'TemplateEntities' è già un'unità di lavoro comunque. –

+0

Incollerò nel mio post il nuovo metodo CreateUser in modo che tu possa dirmi se è un modo migliore. Attendo con ansia la vostra risposta. – gigi

Problemi correlati