هل أستخدم وحدة العمل هنا بشكل صحيح؟ (إطار entityi 4 poco)
-
25-09-2019 - |
سؤال
لقد وجدت بعض الأمثلة على كيفية إنشاء وحدة العمل مع EF4 ، لم أستخدم DI/IOC وأود أن أبقي الأمور بسيطة وهذا مثال (90 ٪ مستوحاة) وأعتقد أنه على ما يرام ولكن بما أنني أبحث عنه نمط لاستخدامه من الآن فصاعدًا ، أود أن أطلب رأيًا آخر مرة.
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();
}
}
وأخيرا
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;
}
}
}
}
}
بعد التخلص إذا كان iUnitofwork و Idisposal يبدو Createuser هكذا:
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;
}
}
}
}
المحلول
هذا يبدو على ما يرام بشكل أساسي. بعض الاقتراحات على الرغم من:
- يجب ألا تدع المستودع يتخلص من
TemplateEntities
. والسبب في ذلك هو أنه عندما تحتاج إلى مستودعين في معاملة واحدة ، لديك مشكلة. يجب عليك تحريك مسؤولية التخلص منTemplateEntities
إلى نفس مستوىTransactionScope
; - ال
TransactionScope
يجب نقلها إلى مستوى أعلى. ويفضل ، وTemplateEntities
يجب إنشاء مثيل له ضمن أTransactionScope
; - ليس عليك إنشاء
Save
غلاف إذا لم يحتوي على وظيفة. إذا قمت بتحديدvoid SaveChanges()
على الIUnitOfWork
الواجهة ، هذا سوف يلتقطSaveChanges
التابعTemplateEntities
; - شخصيا لن يكون لدي
string GetUserNameByEmail(...)
لكن بالأحرىUser GetUserByEmail(...)
لأن هذا سيخدم هذا الغرض أيضًا ولديك ميزة عدم وجود طريقتين تبحث عن عنوان البريد الإلكتروني عندما تحتاج لاحقًا إلىUser GetUserByEmail(...)
; - قد ترغب في التفكير في صنع
ctx
خاص ، أو على الأقل معدي خاص مثلpublic TemplateEntities Ctx { get; private set; }
; - يمكنك إنشاء مستودع مجردة مع طرق مثل المثال أدناه. سيوفر لك هذا الكثير من الكتابة المملة على المدى الطويل:
-
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();
}
/* ... */
}
لا تنتمي إلى StackOverflow