![ç»å](https://habrastorage.org/getpro/habr/post_images/a49/9f5/447/a499f5447b56ad5c5c86afd417c811e1.jpg)
ãã®èšäºã¯ã
ãªãããã ããªã®ã§ããïŒ
MS Entity FrameworkãNHibernateãªã©ã®å·¥æ¥è£œåã¯è€éã§ãåªããæ©èœãåããŠãããå®éã«ã¯ããèªäœãå¥åã®ãã®ã§ãã å€ãã®å Žåããã®ãããªORMããç®çã®åäœãååŸããã«ã¯ããã®ãããªã·ã¹ãã ã®è€éãªæäœã«ç²ŸéããŠããå¥ã®äººãå¿ èŠã§ããããã¯ããŒã éçºã«ã¯é©ããŠããŸããã
æçš¿ã®äž»ãªçè«çæ å ±æºã¯ã Martin Fowlerã®èæž ãPatterns of Enterprise Application ArchitectureïŒP of EAAïŒãã§ãã
å®éã«ORMãDDDãTTDã
äœãååŸãããã§ããïŒ
ããã«çšèªãå®çŸ©ããŸãïŒè¿œè·¡ãšã¯ãä¿åãããããŒã¿ãããã«åæããããã«ãåäžã®ãã©ã³ã¶ã¯ã·ã§ã³å ã§ããžãã¹ãªããžã§ã¯ãã®å€æŽã远跡ããããšãæå³ããŸã
RAMããã³ããŒã¿ããŒã¹ã®å 容ã
ORMã®äž»ãªçš®é¡ã¯äœã§ããïŒ
- .NETã®äžçã§ãã©ããã³ã°ã䜿çšããããã®ORMã«ã¯ãå€æŽã远跡ããå Žåãšå€æŽã远跡ããªãå Žåã®2çš®é¡ããããŸãã
- SQLã¯ãšãªãçæããã¢ãããŒãã«ã€ããŠïŒã¯ãšãªãæ瀺çã«äœ¿çšãããªããžã§ã¯ãã¢ãã«ã®ã¯ãšãªãžã§ãã¬ãŒã¿ãŒã«åºã¥ããŸãã
ããšãã°ãã¯ãšãªã䜿çšãããã¯ãšãªãæ瀺çã«äœ¿çšããæåãªORMã®äžã§ãæãé¡èãªäŸã¯Stack Overflowã®Dapper ORMã§ãã ãã®ãããªORMã®äž»ãªæ©èœã¯ããªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ã¢ãã«ããªããžã§ã¯ãã¢ãã«ã«ãããããããšã§ããäžæ¹ãã¯ã©ã€ã¢ã³ãã¯ããŒã¿ããŒã¹ãžã®ã¯ãšãªã®å€èŠ³ãæ確ã«æ±ºå®ããŸãã
ãªããžã§ã¯ãã¢ãã«ã®è¿œè·¡ããã³ã¯ãšãªãžã§ãã¬ãŒã¿ãŒã®äœ¿çšã«ãããMS Entity Frameworkããã³NHibernateã®åºæ¬æŠå¿µã ãããã®ã¢ãããŒãã®é·æãšçæã¯èæ ®ããŸããã ãã¹ãŠã®ãšãŒã°ã«ãã¯åæ§ã«æçšã§ãããçå®ã¯ã¢ãããŒããçµã¿åãããããšã«ãããŸãã
顧客ïŒã€ãŸããç§ïŒã¯ã远跡ã䜿çšããŠïŒãªãã«ããæ©èœãåããïŒããªããžã§ã¯ãã¢ãã«ã®ã¯ãšãªãžã§ãã¬ãŒã¿ãŒã«åºã¥ããŠORMãäœæããããšèããŠããŸããã Linq2SqlãLinqToEntitiesã䜿çšããã«ãã©ã ã-CïŒèšèªåŒããŒãããSQLã¯ãšãªãçæããŸãïŒã¯ããããŒãã³ã¢ã®ã¿ïŒïŒã
ããã«äœ¿çšã§ããMS Entity Frameworkã«ã¯ãããŒã¿ã®ãããæŽæ°ãšåé€ã«é¢ããåä»ãªåé¡ããããŸããæåã«ããŒã¿ããŒã¹ãããã¹ãŠã®ãªããžã§ã¯ããååŸãã次ã«ãµã€ã¯ã«ã§æŽæ°/åé€ããŠãããããŒã¿ããŒã¹ã«å€æŽãé©çšããå¿ èŠããããŸãã ãã®çµæãããŒã¿ããŒã¹ãžã®åŒã³åºããå¿ èŠä»¥äžã«å€ããªããŸãã ããã§åé¡ã説æããŸã ã ãã®åé¡ã¯ãèšäºã®åŸåã§è§£æ±ºããŸãã
äž»ãªæåã決å®ãã
ã¯ã©ã€ã¢ã³ãã³ãŒããéçºäžã®ã©ã€ãã©ãªãšã©ã®ããã«ããåãããããçŽã¡ã«æ±ºå®ããŸãã ã¯ã©ã€ã¢ã³ãã³ãŒãããå©çšã§ããORMã®äž»èŠã³ã³ããŒãã³ãã匷調ããŸãã
ã¯ã©ã€ã¢ã³ããšORMãšã®å¯Ÿè©±ã®æŠå¿µã¯ãæœè±¡ãªããžããªããã®ç¶æ¿ãšããèãæ¹ã«åºã¥ããŠããŸãã ãŸããã¹ãŒããŒã¯ã©ã¹ãå®çŸ©ããŠãORMãåäœããããžãã¹ãªããžã§ã¯ãã®ã»ãããå¶éããå¿ èŠããããŸãã
åããžãã¹ãªããžã§ã¯ãã¯ãã®ã¿ã€ãå ã§äžæã§ããå¿ èŠããããããçžç¶äººã¯èªåã®èå¥åãæ瀺çã«åå®çŸ©ããå¿ èŠããããŸãã
空ã®ãªããžããªãšããžãã¹ãªããžã§ã¯ãã®ã¹ãŒããŒã¯ã©ã¹
CloneïŒïŒã¡ãœããã¯ã远跡ãããšãã«ãªããžã§ã¯ããã³ããŒããã®ã«äŸ¿å©ã§ãã詳现ã¯ä»¥äžãåç §ããŠãã ããã
public abstract class Repository<T> : IRepository<T> where T : EntityBase,new() { // }
// public abstract class EntityBase : IEntity { // public abstract int Id { get; set; } public object Clone() { return MemberwiseClone(); } }
CloneïŒïŒã¡ãœããã¯ã远跡ãããšãã«ãªããžã§ã¯ããã³ããŒããã®ã«äŸ¿å©ã§ãã詳现ã¯ä»¥äžãåç §ããŠãã ããã
ãŠãŒã¶ãŒã«é¢ããæ å ±ãä¿åããã¯ã©ã€ã¢ã³ãããžãã¹ãªããžã§ã¯ããProfileã¯ã©ã¹ãäœæããŸãã
ORMã§ããžãã¹ãªããžã§ã¯ãã䜿çšããã«ã¯ã3ã€ã®æé ãå¿ èŠã§ãã
- å±æ§ã«åºã¥ããŠããžãã¹ãªããžã§ã¯ããããŒã¿ããŒã¹ã®ããŒãã«ã«ãã€ã³ããã
ã¯ã©ã¹ã¯ã©ã¹// EntityBase [TableName("profile")] public class Profile : EntityBase { // [FieldName("profile_id")] public override int Id { get; } [FieldName("userinfo_id")] public int? UserInfoId { get; set; } [FieldName("role_id")] public int RoleId { get; set; } public string Info { get; set; } }
- åããžãã¹ãªããžã§ã¯ãã®ãªããžããªãå®çŸ©ãã
ãããã¡ã€ã«ãªããžããªã¯æ¬¡ã®ããã«ãªããŸãpublic class ProfileRepository : Repository<Profile> { // public ProfileRepository() : base("PhotoGallery") { // CRUD } }
- ããŒã¿ããŒã¹ãžã®æ¥ç¶æååã圢æãã
æ¥ç¶æååã¯æ¬¡ã®ããã«ãªããŸã<connectionStrings> <add name="PhotoGallery" providerName="System.Data.SqlClient" connectionString="server=PC\SQLEXPRESS; database=db_PhotoGallery"/> </connectionStrings>
å€æŽã远跡ããã«ã¯ãUnitOfWorkãã¿ãŒã³ã䜿çšããã®ãæ £äŸã§ãã UnitOfWorkã®æ¬è³ªã¯ããã¡ã€ã³ãªããžã§ã¯ãã§å®è¡ãããã¢ã¯ã·ã§ã³ã远跡ããŠãã¡ã€ã³ã¡ã¢ãªã«æ ŒçŽãããŠããããŒã¿ãããŒã¿ããŒã¹ã®å 容ãšããã«åæãããããšã§ãã ãã®å Žåãå€æŽã¯äžåºŠã«ãã¹ãŠèšé²ãããŸãã
UnitOfWorkããã³ããšã³ã
public interface IUnitOfWork : IDisposable { void Commit(); }
ããããã¹ãŠã®ããã§ãã ãã ããèæ ®ãã¹ãããšã2ã€ãããŸãã
- å€æŽã®è¿œè·¡ã¯ãçŸåšã®ããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³å šäœã«åœ¹ç«ã¡ããã¹ãŠã®ããžãã¹ãªããžã§ã¯ãã«ã¢ã¯ã»ã¹ã§ããå¿ èŠããããŸãã
- ããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ã¯åäžã®ã¹ã¬ããå ã§å®è¡ããå¿ èŠããããããããŒã«ã«ã¹ã¬ããã¹ãã¢ã䜿çšããŠãäœæ¥åäœãçŸåšå®è¡äžã®ã¹ã¬ããã«é¢é£ä»ããå¿ èŠããããŸãã
UnitOfWorkãªããžã§ã¯ããæ¢ã«ããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³ãããŒã«é¢é£ä»ããããŠããå Žåã¯ããã®ãªããžã§ã¯ãã«é 眮ããå¿ èŠããããŸãã ããã«ãè«ççãªèŠ³ç¹ããèŠããšãäœæ¥ãŠãããã¯ãã®ã»ãã·ã§ã³ã«å±ããŸãã
éçã¯ã©ã¹Sessionã䜿çšããŸã
public static class Session { // private static readonly ThreadLocal<IUnitOfWork> CurrentThreadData = new ThreadLocal<IUnitOfWork>(true); public static IUnitOfWork Current { get { return CurrentThreadData.Value; } private set { CurrentThreadData.Value = value; } } public static IUnitOfWork Create(IUnitOfWork uow) { return Current ?? (Current = uow); } }
远跡ããã«è¡ãå¿ èŠãããå ŽåãSession.CreateãåŒã³åºãããã«ãUnitOfWorkã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããå¿ èŠã¯ãããŸããã
ãããã£ãŠãORMãšããåãããããã«å¿ èŠãªãã¹ãŠã®èŠçŽ ã決å®ããåŸãORMã§äœæ¥ããäŸã瀺ããŸãã
ORMã®äœ¿çšäŸ
var uow = new UnitOfWork(); using (Session.Create(uow)) { var profileRepo = new ProfileRepository(); // uow.Commit(); }
æçãå§ãã
åã«èª¬æããããšã¯ãã¹ãŠãå ¬ééšåã«é¢ãããã®ã§ããã 次ã«ãå éšã®éšåãæ€èšããŸãã ããã«éçºããã«ã¯ã远跡ãããªããžã§ã¯ãã®æ§é ã決å®ããå¿ èŠããããŸãã
ããžãã¹ãªããžã§ã¯ããšè¿œè·¡ãªããžã§ã¯ããæ··åããªãã§ãã ããã
- ããžãã¹ãªããžã§ã¯ãã«ã¯ç¬èªã®ã¿ã€ãããããŸããããã©ããã³ã°ãªããžã§ã¯ãã¯å€ãã®ããžãã¹ãªããžã§ã¯ãã®å€§éæäœã«é©ããŠããå¿ èŠããããŸããã€ãŸããç¹å®ã®ã¿ã€ãã«äŸåããã¹ãã§ã¯ãããŸããã
- 远跡ãªããžã§ã¯ãã¯ãç¹å®ã®ããžãã¹ãã©ã³ã¶ã¯ã·ã§ã³å ã«ååšãããšã³ãã£ãã£ã§ããå€ãã®ããžãã¹ãªããžã§ã¯ãã®äžã§ããã®äžææ§ã¯ãã®ãã©ã³ã¶ã¯ã·ã§ã³ã®ãã¬ãŒã ã¯ãŒã¯å ã§æ±ºå®ããå¿ èŠããããŸã
ãã®ãããªãªããžã§ã¯ãã«ã¯ãããããã£ãå¿ èŠã§ããããšã«ãªããŸãã
- ã¿ã€ãå ã§äžæ
- å€ãããªã
æ¬è³ªçã«ã远跡çšã®ãªããžã§ã¯ãã¯ãããžãã¹ãªããžã§ã¯ããæ ŒçŽããããã®ã³ã³ããã§ãã åè¿°ããããã«ããã¹ãŠã®ã¯ã©ã€ã¢ã³ãããžãã¹ãªããžã§ã¯ãã¯EntityBaseã¹ãŒããŒã¯ã©ã¹ã®ç¥å ã§ããå¿ èŠãããããããã®ãªããžã§ã¯ãèå¥åãåå®çŸ©ããå¿ èŠããããŸãã èå¥åã¯ãåãã€ãŸãããŒã¿ããŒã¹å ã®ããŒãã«å ã§äžææ§ãæäŸããŸãã
远跡çšã®ãªããžã§ã¯ãã³ã³ãããŒã®å®è£
internal struct EntityStruct { // internal Type Key { get; private set; } internal EntityBase Value { get; private set; } internal EntityStruct(Type key, EntityBase value) : this() { Key = key; Value = value; } public override bool Equals(object obj) { if (!(obj is EntityStruct)) { throw new TypeAccessException("EntityStruct"); } return Equals((EntityStruct)obj); } public bool Equals(EntityStruct obj) { if (Value.Id != obj.Value.Id) { return false; } return Key == obj.Key; } public override int GetHashCode() { // , // return (unchecked(25 * Key.GetHashCode()) ^ Value.Id.GetHashCode()) & 0x7FFFFFFF; } }
ããžãã¹ãªããžã§ã¯ãã®è¿œè·¡
远跡çšã®ãªããžã§ã¯ãã®ç»é²ã¯ããªããžããªãããããã®ãªããžã§ã¯ããåä¿¡ãã段éã§è¡ãããŸãã
ããŒã¿ããŒã¹ããããžãã¹ãªããžã§ã¯ããåãåã£ããã远跡çšã®ãªããžã§ã¯ããšããŠç»é²ããå¿ èŠããããŸãã
ãã®ãããªãªããžã§ã¯ãã«ã¯ãããŒã¿ããŒã¹ããã®åä¿¡çŽåŸãšãå€æŽãã³ãããããåã®2ã€ã®ç¶æ ããããŸãã
æåã®ãªããžã§ã¯ãã¯ãã¯ãªãŒã³ãã2çªç®ã®ãªããžã§ã¯ãã¯ãããŒãã£ããªããžã§ã¯ããšåŒã°ããŸãã
äŸ
var uow = new UnitOfWork(); using (Session.Create(uow)) { var profileRepo = new ProfileRepository(); // "" , // "" var profiles = profileRepo.Get(x=>x.Info = " "); // "" foreach (var profile in profiles) { profile.Info = " "; } // uow.Commit(); }
éèŠãªç¹ã¯ããã¯ãªãŒã³ãªããªããžã§ã¯ããä¿æããã«ã¯ãã³ããŒæäœãå¿ èŠã§ãããããã©ãŒãã³ã¹ã«æªåœ±é¿ãåãŒãå¯èœæ§ãããããšã§ãã
äžè¬ã«ã远跡ãªããžã§ã¯ãã¯æäœã®çš®é¡ããšã«ç»é²ããå¿ èŠããããããæŽæ°ãåé€ãæ¿å ¥ã®æäœçšã®ãªããžã§ã¯ããå¿ èŠã§ãã
å€ã«ããæ¯èŒæäœãå¿ èŠãªãå®éã«å€æŽããããªããžã§ã¯ãã®ã¿ãç»é²ããå¿ èŠãããããšãèæ ®ããå¿ èŠããããŸãïŒãªãŒããŒã©ã€ããããEqualsã¡ãœããã䜿çšããEntityStructæ§é ã®å®è£ ã¯äžèšã§æäŸãããŠããŸãïŒã æçµçã«ãæ¯èŒæäœã¯ããã·ã¥ã®æ¯èŒã«éå®ãããŸãã
远跡ãªããžã§ã¯ãã®ç»é²ã®ã€ãã³ãã¯ãCRUDã¡ãœããã®ãªããžããªã®æœè±¡ã¯ã©ã¹ã®æ©èœããçºçããŸãã
远跡ãªããžã§ã¯ãç»é²æ©èœã®å®è£
internal interface IObjectTracker { // ICollection<EntityStruct> NewObjects { get; } ICollection<EntityStruct> ChangeObjects { get; } // void RegInsertedNewObjects(object sender, AddObjInfoEventArgs e); void RegCleanObjects(object sender, DirtyObjsInfoEventArgs e); } internal class DefaultObjectTracker : IObjectTracker { // - "" , - "" private readonly Dictionary<EntityStruct, EntityStruct> _dirtyCreanPairs; public ICollection<EntityStruct> NewObjects { get; private set; } public ICollection<EntityStruct> ChangeObjects { get { // return _dirtyCreanPairs.GetChangesObjects(); } } internal DefaultObjectTracker() { NewObjects = new Collection<EntityStruct>(); // boxing/unboxing EqualityComparer _dirtyCreanPairs = new Dictionary<EntityStruct, EntityStruct>(new IdentityMapEqualityComparer()); } public void RegInsertedNewObjects(object sender, AddObjInfoEventArgs e) { NewObjects.Add(e.InsertedObj); } public void RegCleanObjects(object sender, DirtyObjsInfoEventArgs e) { var objs = e.DirtyObjs; foreach (var obj in objs) { if (!_dirtyCreanPairs.ContainsKey(obj)) { // "" MemberwiseClone() var cloneObj = new EntityStruct(obj.Key, (EntityBase)obj.Value.Clone()); _dirtyCreanPairs.Add(obj, cloneObj); } } } }
ã¯ã©ã€ã¢ã³ãã«ãã£ãŠå€æŽããããªããžã§ã¯ããèå¥ããæ©èœ
public static ICollection<EntityStruct> GetChangesObjects ( this Dictionary<EntityStruct, EntityStruct> dirtyCleanPairs ) { var result = new List<EntityStruct>(); foreach (var cleanObj in dirtyCleanPairs.Keys) { if (!(cleanObj.Key == dirtyCleanPairs[cleanObj].Key)) { throw new Exception("incorrect types"); } if (ChangeDirtyObjs(cleanObj.Value, dirtyCleanPairs[cleanObj].Value, cleanObj.Key)) { result.Add(cleanObj); } } return result; } public static bool ChangeDirtyObjs(EntityBase cleanObj, EntityBase dirtyObj, Type type) { var props = type.GetProperties(); // foreach (var prop in props) { var cleanValue = prop.GetValue(cleanObj, null); var dirtyValue = prop.GetValue(dirtyObj, null); // , if (!cleanValue.Equals(dirtyValue)) { return true; } } return false; }
1ã€ã®ãã©ã³ã¶ã¯ã·ã§ã³ã®ããžãã¹ãªããžã§ã¯ãã¯ç°ãªãããŒã¿ããŒã¹ããã®ãã®ã§ããå¯èœæ§ãããããšã«æ³šæããŠãã ããã åããŒã¿ããŒã¹ã«å¯ŸããŠã远跡ã®ç¬èªã®ã€ã³ã¹ã¿ã³ã¹ïŒIObjectTrackerãå®è£ ããã¯ã©ã¹ãããšãã°DefaultObjectTrackerïŒãå®çŸ©ããå¿ èŠããããšæ³å®ããã®ã¯è«ççã§ãã
çŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ãããŒã¿ããŒã¹ã远跡ãããå ã®ãæ¢ç¥ãã§ããå¿ èŠããããŸãã UnitOfWorkã®ã€ã³ã¹ã¿ã³ã¹ãäœæãã段éã§ãæ§æãã¡ã€ã«ã§æå®ãããããŒã¿ããŒã¹æ¥ç¶ã䜿çšããŠã远跡ãªããžã§ã¯ãã®ã€ã³ã¹ã¿ã³ã¹ïŒDefaultObjectTrackerã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ïŒãåæåããå¿ èŠããããŸãã
UnitOfWorkã®ã¯ã©ã¹ãå€æŽããŸããã
internal interface IDetector { // - , - Dictionary<string, IObjectTracker> ObjectDetector { get; } } public sealed class UnitOfWork : IUnitOfWork, IDetector { private readonly Dictionary<string, IObjectTracker> _objectDetector; Dictionary<string, IObjectTracker> IDetector.ObjectDetector { get { return _objectDetector; } } public UnitOfWork() { _objectDetector = new Dictionary<string, IObjectTracker>(); foreach (ConnectionStringSettings conName in ConfigurationManager.ConnectionStrings) { // _objectDetector.Add(conName.Name, new DefaultObjectTracker()); } } }
ãã©ã³ã¶ã¯ã·ã§ã³å ã®ãã¹ãŠã®ãªããžããªã€ã³ã¹ã¿ã³ã¹ã§äœ¿çšã§ããããŒã¿ããŒã¹ã«å¯Ÿå¿ãã远跡ã€ã³ã¹ã¿ã³ã¹ã«é¢ããæ å ±ã éçSessionã¯ã©ã¹ã«åäžã®ã¢ã¯ã»ã¹ãã€ã³ããäœæãããšäŸ¿å©ã§ãã
ã»ãã·ã§ã³ã¯ã©ã¹ã®åœ¢åŒ
public static class Session { private static readonly ThreadLocal<IUnitOfWork> CurrentThreadData = new ThreadLocal<IUnitOfWork>(true); public static IUnitOfWork Current { get { return CurrentThreadData.Value; } private set { CurrentThreadData.Value = value; } } public static IUnitOfWork Create(IUnitOfWork uow) { return Current ?? (Current = uow); } // // internal static IObjectTracker GetObjectTracker(string connectionName) { var uow = Current; if (uow == null) { throw new ApplicationException(" Create unit of work context and using Session."); } var detector = uow as IDetector; if (detector == null) { throw new ApplicationException("Create unit of work context and using Session."); } return detector.ObjectDetector[connectionName]; } } }
ããŒã¿ã¢ã¯ã»ã¹
ããŒã¿ã¢ã¯ã»ã¹æ©èœã¯ãããŒã¿ããŒã¹ã¢ã¯ã»ã¹ã¡ãœãããçŽæ¥åŒã³åºããŸãã ãã®æ©èœã¯ãCRUDã¡ãœããã®æœè±¡ãªããžããªã¯ã©ã¹ã«ãã£ãŠäœ¿çšãããŸãã åçŽãªå ŽåãããŒã¿ã¢ã¯ã»ã¹ã¯ã©ã¹ã«ã¯ãããŒã¿ãæäœããããã®CRUDã¡ãœãããå«ãŸããŸãã
DbProviderã¯ã©ã¹ã®å®è£
internal interface IDataSourceProvider : IDisposable { State State { get; } // , void Commit(ICollection<EntityStruct> updObjs); ICollection<T> GetByFields<T>(BinaryExpression exp) where T : EntityBase, new(); } internal class DbProvider : IDataSourceProvider { private IDbConnection _connection; internal DbProvider(IDbConnection connection) { _connection = connection; State = State.Open; } public State State { get; private set; } public ICollection<T> GetByFields<T>(BinaryExpression exp) where T : EntityBase, new() { // select- exp Func<IDbCommand, BinaryExpression, string> cmdBuilder = SelectCommandBulder.Create<T>; ICollection<T> result; using (var conn = _connection) { using (var command = conn.CreateCommand()) { command.CommandText = cmdBuilder.Invoke(command, exp); command.CommandType = CommandType.Text; conn.Open(); result = command.ExecuteListReader<T>(); } } State = State.Close; return result; } public void Commit(ICollection<EntityStruct> updObjs) { if (updObjs.Count == 0) { return; } // - update- exp // - var cmdBuilder = new Dictionary<Func<IDbCommand, ICollection<EntityStruct>, string>, ICollection<EntityStruct>>(); cmdBuilder.Add(UpdateCommandBuilder.Create, updObjs); ExecuteNonQuery(cmdBuilder, packUpdDict, packDeleteDict); } private void ExecuteNonQuery(Dictionary<Func<IDbCommand, ICollection<EntityStruct>, string>, ICollection<EntityStruct>> cmdBuilder) { using (var conn = _connection) { using (var command = conn.CreateCommand()) { var cmdTxtBuilder = new StringBuilder(); foreach (var builder in cmdBuilder) { cmdTxtBuilder.Append(builder.Key.Invoke(command, builder.Value)); } command.CommandText = cmdTxtBuilder.ToString(); command.CommandType = CommandType.Text; conn.Open(); if (command.ExecuteNonQuery() < 1) throw new ExecuteQueryException(command); } } State = State.Close; } private ICollection<T> ExecuteListReader<T>(EntityStruct objs) where T : EntityBase, IEntity, new() { Func<IDbCommand, EntityStruct, string> cmdBuilder = SelectCommandBulder.Create; ICollection<T> result; using (var conn = _connection) { using (var command = conn.CreateCommand()) { command.CommandText = cmdBuilder.Invoke(command, objs); command.CommandType = CommandType.Text; conn.Open(); result = command.ExecuteListReader<T>(); } } State = State.Close; return result; } private void Dispose() { if (State == State.Open) { _connection.Close(); State = State.Close; } _connection = null; GC.SuppressFinalize(this); } void IDisposable.Dispose() { Dispose(); } ~DbProvider() { Dispose(); } }
DbProviderã¯ã©ã¹ã«ã¯ãããŒã¿ããŒã¹ãžã®æ¢åã®æ¥ç¶ãå¿ èŠã§ãã ãã¡ã¯ããªã¡ãœããã«åºã¥ããŠãæ¥ç¶ãšè¿œå ã®ã€ã³ãã©ã¹ãã©ã¯ãã£ã®äœæãå¥ã®ã¯ã©ã¹ã«å§ä»»ããŸãã ãããã£ãŠããã¡ã¯ããªã®è£å©ã¯ã©ã¹ãä»ããŠã®ã¿DbProviderã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããå¿ èŠããããŸãã
DbProvider Factoryã¡ãœãã
class DataSourceProviderFactory { static DbConnection CreateDbConnection(string connectionString, string providerName) { if (string.IsNullOrWhiteSpace(connectionString)) { throw new ArgumentException("connectionString is null or whitespace"); } DbConnection connection; DbProviderFactory factory; try { factory = DbProviderFactories.GetFactory(providerName); connection = factory.CreateConnection(); if (connection != null) connection.ConnectionString = connectionString; } catch (ArgumentException) { try { factory = DbProviderFactories.GetFactory("System.Data.SqlClient"); connection = factory.CreateConnection(); if (connection != null) { connection.ConnectionString = connectionString; } } catch (Exception) { throw new Exception("DB connection has been failed."); } } return connection; } public static IDataSourceProvider Create(string connectionString) { var settings = ConfigurationManager.ConnectionStrings[connectionString]; var dbConn = CreateDbConnection(settings.ConnectionString, settings.ProviderName); return new DbProvider(dbConn); } public static IDataSourceProvider CreateByDefaultDataProvider(string connectionString) { var dbConn = CreateDbConnection(connectionString, string.Empty); return new DbProvider(dbConn); } }
远跡ãªããžã§ã¯ãã®ç»é²ã¯ããªããžããªã®CRUDã¡ãœããã§è¡ãããå¿ èŠããããCRUDã¡ãœããã¯æ©èœãããŒã¿ã¢ã¯ã»ã¹ã¬ã€ã€ãŒã«å§ä»»ããŸãã ãããã£ãŠããã©ããã³ã°ãèæ ®ãããšãIDataSourceProviderã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ãå¿ èŠã§ãã ãã®ã¯ã©ã¹ã§è奮ããã€ãã³ãã®ã¡ã«ããºã ã«åºã¥ããŠãªããžã§ã¯ããç»é²ããŸãã IDataSourceProviderã€ã³ã¿ãŒãã§ã€ã¹ã®æ³å®ãããæ°ããå®è£ ã¯ã远跡ã®ããã«ç»é²ã€ãã³ããéå§ããããŒã¿ããŒã¹ã«ã¢ã¯ã»ã¹ã§ããå¿ èŠããããŸãã ãã®å ŽåãDbProviderã¯ã©ã¹ãè£ é£ŸãããšäŸ¿å©ã§ãã
TrackerProviderã¯ã©ã¹ã®å®è£
internal class TrackerProvider : IDataSourceProvider { private event EventHandler<DirtyObjsInfoEventArgs> DirtyObjEvent; private event EventHandler<UpdateObjsInfoEventArgs> UpdateObjEvent; private readonly IDataSourceProvider _dataSourceProvider; private readonly string _connectionName; private readonly object _syncObj = new object(); private IObjectTracker ObjectTracker { get { lock (_syncObj) { // return Session.GetObjectTracker(_connectionName); } } } public TrackerProvider(string connectionName) { _connectionName = connectionName; _dataSourceProvider = DataSourceProviderFactory.Create(_connectionName); // RegisterEvents(); } public State State { get { return _dataSourceProvider.State; } } private void RegisterEvents() { // if (Session.Current == null) { throw new ApplicationException("Session has should be used. Create a session."); }; // DirtyObjEvent += ObjectTracker.RegCleanObjects; UpdateObjEvent += ObjectTracker.RegUpdatedObjects; } public ICollection<T> GetByFields<T>(BinaryExpression exp) where T : EntityBase, IEntity, new() { // DbProvider var result = _dataSourceProvider.GetByFields<T>(exp); var registratedObjs = result.Select(r => new EntityStruct(typeof(T), r)).ToList(); // "" var handler = DirtyObjEvent; if (handler == null) return result; handler(this, new DirtyObjsInfoEventArgs(registratedObjs)); return result; } public void Commit(ICollection<EntityStruct> updObjs) { // DbProvider _dataSourceProvider.Commit(updObjs, delObjs, addObjs, packUpdObjs, deleteUpdObjs); } public void Dispose() { _dataSourceProvider.Dispose(); } }
å°èš
ãããªãã¯ã¯ã©ã¹ãã©ã®ããã«èŠããããèŠãŠã¿ãŸãããã
äžèšã®ããã«ããªããžããªã¯ã©ã¹ã¯ãã®æ©èœãIDataSourceProviderã€ã³ã¿ãŒãã§ã€ã¹å®è£ ã«å§ä»»ããå¿ èŠããããŸãã ã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ãããæ¥ç¶æååã«åºã¥ããŠãªããžããªã¯ã©ã¹ãåæåãããšãããã©ããã³ã°ã®äœ¿çšã«å¿ããŠãIDataSourceProviderã®å¿ èŠãªå®è£ ãäœæããå¿ èŠããããŸãã ãŸããããŒã¿ã¢ã¯ã»ã¹ã¯ã©ã¹ãããŒã¿ããŒã¹ãžã®æ¥ç¶ããã€ã§ãã倱ããå¯èœæ§ãããããšãèæ ®ããå¿ èŠããããŸãããã®ãããããããã£ã䜿çšããŠãã®æ¥ç¶ãç£èŠããŸãã
åè¿°ã®ããã«ãUnitOfWorkã¯ã©ã¹ã¯ããã®ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãããŒã¿ããŒã¹æ¥ç¶æååã§äœ¿çšå¯èœãªãã¹ãŠã«åŸã£ãŠãDefaultObjectTrackerã¯ã©ã¹ã®ãªããžã§ã¯ãã®ãªã¹ããäœæããå¿ èŠããããŸãã å€æŽã®ä¿®æ£ããã¹ãŠã®ããŒã¿ããŒã¹ã§çºçããå¿ èŠãããããšã¯è«ççã§ãã远跡ã€ã³ã¹ã¿ã³ã¹ããšã«ãå€æŽãä¿®æ£ããã¡ãœãããåŒã³åºãããŸãã
Public-ã¯ã©ã¹ã¯æ¬¡ã®åœ¢åŒãåããŸã
public abstract class Repository<T> : IRepository<T> where T : EntityBase, IEntity, new() { private readonly object _syncObj = new object(); private IDataSourceProvider _dataSourceProvider; //c "" private IDataSourceProvider DataSourceProvider { get { lock (_syncObj) { if (_dataSourceProvider.State == State.Close) { _dataSourceProvider = GetDataSourceProvider(); } return _dataSourceProvider; } } } private readonly string _connectionName; protected Repository(string connectionName) { if (string.IsNullOrWhiteSpace(connectionName)) { throw new ArgumentNullException("connectionName"); } _connectionName = connectionName; var dataSourceProvider = GetDataSourceProvider(); if (dataSourceProvider == null) { throw new ArgumentNullException("dataSourceProvider"); } _dataSourceProvider = dataSourceProvider; } private IDataSourceProvider GetDataSourceProvider() { // DbProvider' // //// - TrackerProvider return Session.Current == null ? DataSourceProviderFactory.Create(_connectionName) : new TrackerProvider(_connectionName); } public ICollection<T> Get(Expression<Func<T, bool>> exp) { return DataSourceProvider.GetByFields<T>(exp.Body as BinaryExpression); } } public sealed class UnitOfWork : IUnitOfWork, IDetector { private readonly Dictionary<string, IObjectTracker> _objectDetector; Dictionary<string, IObjectTracker> IDetector.ObjectDetector { get { return _objectDetector; } } public UnitOfWork() { _objectDetector = new Dictionary<string, IObjectTracker>(); foreach (ConnectionStringSettings conName in ConfigurationManager.ConnectionStrings) { _objectDetector.Add(conName.Name, new DefaultObjectTracker()); } } public void Commit() { SaveChanges(); } private void SaveChanges() { foreach (var objectDetector in _objectDetector) { // var provider = new TrackerProvider(objectDetector.Key); provider.Commit( objectDetector.Value.ChangeObjects, objectDetector.Value.DeletedObjects, objectDetector.Value.NewObjects, objectDetector.Value.UpdatedObjects, objectDetector.Value.DeletedWhereExp); } } }
èšäºã®ç¶ãã§ã¯ãé¢é£ãããšã³ãã£ãã£ã®æäœãåŒããªãŒã«åºã¥ãSQLã¯ãšãªã®çæãããŒã¿ã®äžæ¬åé€/å€æŽæ¹æ³ïŒUpdateWhereãRemoveWhereãªã©ïŒãæ€èšããŸãã
åçŽåããã«ããããžã§ã¯ãã®ãœãŒã¹ã³ãŒãå šäœãããã«ãããŸã ã