Verwende ich richtig Unit of Work hier? (Entityi Framework 4 POCO)
-
25-09-2019 - |
Frage
fand ich einige Beispiele dafür, wie mit EF4 Arbeitseinheit zu schaffen, ich habe di / ioc nicht verwendet, und ich mag die Dinge einfach halten und dies ist ein Beispiel (90% inspiriert) und ich denke, es ist in Ordnung, aber da ich bei einem Muster Verwendung von jetzt ist auf der Suche auf ich einer Meinung ein letztes Mal fragen möchte.
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();
}
}
Und schließlich
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;
}
}
}
}
}
Nach loszuwerden, wenn die IUnitOfWork und IDisposal die AngelegtVon sieht wie folgt aus:
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;
}
}
}
}
Lösung
Das sieht im Grunde OK. Einige Vorschläge aber:
- Sie sollten nicht zulassen, das Repository die
TemplateEntities
entsorgen. Der Grund dafür ist, dass, wenn Sie benötigen zwei Repositories innerhalb einer Transaktion, Sie haben ein Problem. Sie sollten die Verantwortung für die Entsorgung desTemplateEntities
auf das gleiche Niveau wie dieTransactionScope
bewegen; - Die
TransactionScope
sollte auf ein höheres Niveau bewegt werden. Vorzugsweise sollte dieTemplateEntities
innerhalb einesTransactionScope
instanziert werden; - Sie müssen nicht die
Save
Wrapper erstellen, wenn es keine Funktionalität enthält. Wenn Sie denvoid SaveChanges()
auf derIUnitOfWork
Schnittstelle angeben, wird dies dieSaveChanges
derTemplateEntities
abholen; - Persönlich würde ich nicht
string GetUserNameByEmail(...)
hat, sondernUser GetUserByEmail(...)
denn dann wird dies auch Ihren Zweck dienen und Sie haben den Vorteil, nicht zwei Methoden, die die Suche nach E-Mail-Adresse, wenn Sie dieUser GetUserByEmail(...)
später müssen; - Sie können
ctx
privat zu machen oder zumindest eine private Setter wiepublic TemplateEntities Ctx { get; private set; }
denken wollen; - Sie könnten ein abstraktes Repository mit Methoden wie im folgenden Beispiel erstellen. Dies wird Ihnen viel dumpfer Typisierung auf lange Sicht speichern:
-
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();
}
/* ... */
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow