दिलचस्प पोस्ट
IIS पर ASP.NET के लिए सही फ़ाइल अनुमतियां कैसे सेट करें I लाखों रिकॉर्ड के साथ SQLite में कुशल पेजिंग क्या त्रुटि हो रही है: संदर्भित तालिका के लिए कोई भी अद्वितीय बाधाओं से मेल खाने वाली कुंजियां नहीं हैं? ASP.NET MVC रूटिंग – मार्गों के लिए .html एक्सटेंशन जोड़ें MVC3.0 में चेकबॉक्स सूची कैसे link_to के साथ बूटस्ट्रैप modal जोड़ने के लिए ताकि लिंक सामग्री सामग्री में खुला? वीबी 6 से वेब सेवा का उपभोग करने का सबसे अच्छा तरीका क्या है? जिस तरह से फ़ायरबेज डेटाबेस क्विकस्टार्ट सुरक्षित हैं, वह गिनती सुरक्षित है? कन्स्ट्रक्टर को इंगित करने वाला फ़ंक्शन पॉइंटर कैसे पास करें? पायथन गुण कैसे काम करता है? जावास्क्रिप्ट में पूरे शब्द का मिलान PHP में die () और exit () में अंतर क्या हैं? सुडो एको "कुछ" >> / etc / विशेषाधिकारितफ़ाइल काम नहीं कर रहा है … क्या कोई विकल्प है? क्या XAML में कैनवास के बच्चों की संपत्ति बाँधना संभव है? PHP – mysql अद्यतन का पता लगाता / प्रविष्टि विफलता का उल्लंघन हुआ अनन्य बाध्यता के कारण

IOC का उपयोग कर रिपॉजिटरी से कार्य कार्यक्षमता की यूनिट को कैसे हटाएं I

मेरे पास एएसपी.नेट एमवीसी, यूनिटी, और लिनक टू एसक्यूएल का उपयोग करने वाला एक एप्लीकेशन है I

एकता कंटेनर एक प्रकार की AcmeDataContext पंजीकृत करता है जो AcmeDataContext से प्राप्त होता है, जिसमें AcmeDataContext का इस्तेमाल करते हुए एक LifetimeManager

एक नियंत्रक कारखाना है जो एकता कंटेनर का उपयोग करते हुए नियंत्रक उदाहरण देता है। मैं कंसल्टेंट्स पर मेरी सारी निर्भरताएं सेट करता हूं, जैसे:

 // Initialize a new instance of the EmployeeController class public EmployeeController(IEmployeeService service) // Initializes a new instance of the EmployeeService class public EmployeeService(IEmployeeRepository repository) : IEmployeeService // Initialize a new instance of the EmployeeRepository class public EmployeeRepository(AcmeDataContext dataContext) : IEmployeeRepository 

जब भी कन्स्ट्रक्टर की आवश्यकता होती है, एकता कंटेनर एक कनेक्शन का हल करता है, जिसका उपयोग डेटा संदर्भ को हल करने के लिए किया जाता है, फिर एक रिपॉजिटरी, फिर सेवा, और अंत में नियंत्रक

मुद्दा यह है कि IEmployeeRepository , SubmitChanges विधि का पर्दाफाश करता है, क्योंकि सेवा कक्षाओं में IEmployeeRepository संदर्भ नहीं है।

मुझे बताया गया है कि कार्य की इकाई को रिपॉजिटरी के बाहर से प्रबंधित किया जाना चाहिए, इसलिए मुझे लगता है कि मुझे अपने रिपॉजिटरीज से SubmitChanges को हटाना चाहिए। ऐसा क्यों है?

यदि यह सत्य है, तो क्या इसका मतलब यह है कि मुझे एक IUnitOfWork इंटरफ़ेस घोषित करना IUnitOfWork और हर सेवा वर्ग पर निर्भर होना चाहिए? मैं अपनी सेवा कक्षाओं को काम की इकाई को कैसे प्रबंधित करने की अनुमति दे सकता हूँ?

Solutions Collecting From Web of "IOC का उपयोग कर रिपॉजिटरी से कार्य कार्यक्षमता की यूनिट को कैसे हटाएं I"

आप खुद AcmeDataContext में AcmeDataContext आपूर्ति करने की कोशिश नहीं करनी चाहिए। मैं पूरी चीज को भी बदलूंगा:

  1. एक कारखाना परिभाषित करें जो Acme डोमेन के लिए कार्य की एक नई इकाई बनाने की अनुमति देता है:
  2. एक अमूर्त AcmeUnitOfWork बनाएँ जो कि LINQ से SQL को दूर करता है
  3. एक ठोस कारखाना बनाएं जो कि नए LINQ को कार्य के एसक्यूएल इकाई बनाने की अनुमति दे सकता है।
  4. अपने डि कॉन्फ़िगरेशन में ठोस कारखाना रजिस्टर करें
  5. इकाई परीक्षण के लिए एक InMemoryAcmeUnitOfWork लागू करें
  6. वैकल्पिक रूप से आपके IQueryable<T> रिपॉजिटरी पर सामान्य कार्यों के लिए सुविधाजनक एक्सटेंशन विधियों को कार्यान्वित करें

अद्यतनः मैंने इस विषय पर एक ब्लॉग पोस्ट लिखा था: अपने LINQ प्रदाता को फिक्स करना ।

नीचे उदाहरण के साथ एक कदम-दर-चरण है:

चेतावनी: यह एक सख्त पोस्ट होगा।

चरण 1: कारखाना को परिभाषित करना:

 public interface IAcmeUnitOfWorkFactory { AcmeUnitOfWork CreateNew(); } 

फ़ैक्ट्री बनाना महत्वपूर्ण है, क्योंकि DataContext को IDisposable लागू किया जाता है, इसलिए आप इस उदाहरण पर स्वामित्व चाहते हैं। जबकि कुछ फ़्रेमवर्क आपको ऑब्जेक्ट्स को निपटाने के लिए अनुमति नहीं देता है, इसके लिए फ़ैक्ट्रीज़ इसे बहुत स्पष्ट करते हैं

चरण 2: Acme डोमेन के लिए काम की एक सार इकाई बनाना:

 public abstract class AcmeUnitOfWork : IDisposable { public IQueryable<Employee> Employees { [DebuggerStepThrough] get { return this.GetRepository<Employee>(); } } public IQueryable<Order> Orders { [DebuggerStepThrough] get { return this.GetRepository<Order>(); } } public abstract void Insert(object entity); public abstract void Delete(object entity); public abstract void SubmitChanges(); public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } protected abstract IQueryable<T> GetRepository<T>() where T : class; protected virtual void Dispose(bool disposing) { } } 

इस सार वर्ग के बारे में ध्यान देने के लिए कुछ दिलचस्प बातें हैं कार्य नियंत्रण इकाई और रिपॉजिटरीज बनाता है। एक रिपॉजिटरी मूल रूप से कुछ है जो IQueryable<T> लागू करता है IQueryable<T> रिपॉजिटरी गुणों का कार्यान्वयन करती है जो एक विशिष्ट रिपॉजिटरी लौटाते हैं। यह uow.GetRepository<Employee>() को कॉल करने से उपयोगकर्ताओं को रोकता है। uow.GetRepository<Employee>() और यह एक ऐसा मॉडल बनाता है जो कि आप LINQ से SQL या Entity Framework के साथ पहले से ही कर रहे हैं।

कार्य की इकाई कार्यान्वित Insert और Delete कार्यवाही LINQ से एसक्यूएल में इन ऑपरेशंस को Table<T> कक्षाओं में रखा गया है, लेकिन जब आप इसे इस तरह कार्यान्वित करने का प्रयास करेंगे तो यह आपको LINQ से SQL को सार करने के लिए रोक देगा।

चरण 3. एक ठोस कारखाना बनाएं:

 public class LinqToSqlAcmeUnitOfWorkFactory : IAcmeUnitOfWorkFactory { private static readonly MappingSource Mapping = new AttributeMappingSource(); public string AcmeConnectionString { get; set; } public AcmeUnitOfWork CreateNew() { var context = new DataContext(this.AcmeConnectionString, Mapping); return new LinqToSqlAcmeUnitOfWork(context); } } 

फैक्ट्री ने AcmeUnitOfWork बेस क्लास के आधार पर एक AcmeUnitOfWork बनाया:

 internal sealed class LinqToSqlAcmeUnitOfWork : AcmeUnitOfWork { private readonly DataContext db; public LinqToSqlAcmeUnitOfWork(DataContext db) { this.db = db; } public override void Insert(object entity) { if (entity == null) throw new ArgumentNullException("entity"); this.db.GetTable(entity.GetType()).InsertOnSubmit(entity); } public override void Delete(object entity) { if (entity == null) throw new ArgumentNullException("entity"); this.db.GetTable(entity.GetType()).DeleteOnSubmit(entity); } public override void SubmitChanges(); { this.db.SubmitChanges(); } protected override IQueryable<TEntity> GetRepository<TEntity>() where TEntity : class { return this.db.GetTable<TEntity>(); } protected override void Dispose(bool disposing) { this.db.Dispose(); } } 

चरण 4: अपने डि कॉन्फ़िगरेशन में ठोस कारखाने को पंजीकृत करें

आप स्वयं को जानते हैं कि IAcmeUnitOfWorkFactory इंटरफ़ेस को LinqToSqlAcmeUnitOfWorkFactory का एक उदाहरण देने के लिए कैसे पंजीकृत किया IAcmeUnitOfWorkFactory , लेकिन यह कुछ ऐसा दिखाई देगा:

 container.RegisterSingle<IAcmeUnitOfWorkFactory>( new LinqToSqlAcmeUnitOfWorkFactory() { AcmeConnectionString = AppSettings.ConnectionStrings["ACME"].ConnectionString }); 

अब आप IAcmeUnitOfWorkFactory का उपयोग करने के लिए EmployeeService पर निर्भरता को बदल सकते हैं:

 public class EmployeeService : IEmployeeService { public EmployeeService(IAcmeUnitOfWorkFactory contextFactory) { ... } public Employee[] GetAll() { using (var context = this.contextFactory.CreateNew()) { // This just works like a real L2S DataObject. return context.Employees.ToArray(); } } } 

ध्यान दें कि आप यहां तक ​​कि IEmployeeService इंटरफ़ेस को निकाल सकते हैं और नियंत्रक को EmployeeService सीधे उपयोग कर सकते हैं। आपको यूनिट परीक्षण के लिए इस इंटरफ़ेस की ज़रूरत नहीं है, क्योंकि आप डेटाबेस को एक्सेस करने से EmployeeService को रोकने के परीक्षण के दौरान काम की इकाई को बदल सकते हैं। यह संभवतः आपको बहुत सारे डि कॉन्फ़िगरेशन को बचाएगा, क्योंकि अधिकांश डि फ्रेमवर्क एक ठोस वर्ग को इन्स्तांत करने का तरीका जानते हैं।

चरण 5: इकाई परीक्षण के लिए एक InMemoryAcmeUnitOfWork लागू करें।

इन सभी अवशेषों के कारण एक कारण हैं इकाई का परीक्षण। अब इकाई परीक्षण उद्देश्यों के लिए एक AcmeUnitOfWork बनाते हैं:

 public class InMemoryAcmeUnitOfWork: AcmeUnitOfWork, IAcmeUnitOfWorkFactory { private readonly List<object> committed = new List<object>(); private readonly List<object> uncommittedInserts = new List<object>(); private readonly List<object> uncommittedDeletes = new List<object>(); // This is a dirty trick. This UoW is also it's own factory. // This makes writing unit tests easier. AcmeUnitOfWork IAcmeUnitOfWorkFactory.CreateNew() { return this; } // Get a list with all committed objects of the requested type. public IEnumerable<TEntity> Committed<TEntity>() where TEntity : class { return this.committed.OfType<TEntity>(); } protected override IQueryable<TEntity> GetRepository<TEntity>() { // Only return committed objects. Same behavior as L2S and EF. return this.committed.OfType<TEntity>().AsQueryable(); } // Directly add an object to the 'database'. Useful during test setup. public void AddCommitted(object entity) { this.committed.Add(entity); } public override void Insert(object entity) { this.uncommittedInserts.Add(entity); } public override void Delete(object entity) { if (!this.committed.Contains(entity)) Assert.Fail("Entity does not exist."); this.uncommittedDeletes.Add(entity); } public override void SubmitChanges() { this.committed.AddRange(this.uncommittedInserts); this.uncommittedInserts.Clear(); this.committed.RemoveAll( e => this.uncommittedDeletes.Contains(e)); this.uncommittedDeletes.Clear(); } protected override void Dispose(bool disposing) { } } 

आप अपने यूनिट परीक्षणों में इस वर्ग का उपयोग कर सकते हैं। उदाहरण के लिए:

 [TestMethod] public void ControllerTest1() { // Arrange var context = new InMemoryAcmeUnitOfWork(); var controller = new CreateValidController(context); context.AddCommitted(new Employee() { Id = 6, Name = ".NET Junkie" }); // Act controller.DoSomething(); // Assert Assert.IsTrue(ExpectSomething); } private static EmployeeController CreateValidController( IAcmeUnitOfWorkFactory factory) { return new EmployeeController(return new EmployeeService(factory)); } 

चरण 6: वैकल्पिक रूप से सुविधाजनक एक्सटेंशन विधियां लागू करें:

रिपॉजिटरीज के पास सुविधाजनक तरीके हैं जैसे GetById या GetByLastName बेशक IQueryable<T> एक सामान्य इंटरफ़ेस है और इसमें ऐसी विधियां शामिल नहीं हैं IQueryable<T> हम अपने कोड को context.Employees.Single(e => e.Id == employeeId) कॉल कर सकते हैं। context.Employees.Single(e => e.Id == employeeId) , लेकिन यह वाकई बदसूरत है। इस समस्या का सही समाधान है: विस्तार विधियां:

 // Place this class in the same namespace as your LINQ to SQL entities. public static class AcmeRepositoryExtensions { public static Employee GetById(this IQueryable<Employee> repository,int id) { return Single(repository.Where(entity => entity.Id == id), id); } public static Order GetById(this IQueryable<Order> repository, int id) { return Single(repository.Where(entity => entity.Id == id), id); } // This method allows reporting more descriptive error messages. [DebuggerStepThrough] private static TEntity Single<TEntity, TKey>(IQueryable<TEntity> query, TKey key) where TEntity : class { try { return query.Single(); } catch (Exception ex) { throw new InvalidOperationException("There was an error " + "getting a single element of type " + typeof(TEntity) .FullName + " with key '" + key + "'. " + ex.Message, ex); } } } 

इन एक्सटेंशन विधियों के साथ, आप उन GetById और अपने कोड से अन्य विधियों को कॉल करने की अनुमति देते हैं:

 var employee = context.Employees.GetById(employeeId); 

क्या सबसे अच्छा बात इस कोड के बारे में है (मैं इसे उत्पादन में उपयोग करता हूं) वह जगह है – यह आपको इकाई परीक्षण के लिए बहुत सारे कोड लिखने से बचाता है आप अपने आप AcmeRepositoryExtensions वर्ग और गुणों को AcmeUnitOfWork वर्ग में जोड़ AcmeUnitOfWork जब नई संस्थाओं को सिस्टम में जोड़ दिया जाएगा, लेकिन आपको उत्पादन या परीक्षण के लिए नई रिपॉज़िटरी कक्षाएं बनाने की आवश्यकता नहीं है।

इस मॉडल में निश्चित रूप से कुछ कमियां हैं शायद सबसे महत्वपूर्ण यह है कि LINQ से SQL पूरी तरह से पूरी तरह से दूर नहीं है, क्योंकि आप अभी भी LINQ से SQL जनरेटेड संस्थाओं का उपयोग करते हैं। उन संस्थाओं में EntitySet<T> गुण हैं जो LINQ से SQL के लिए विशिष्ट हैं। मैंने उन्हें उचित इकाई परीक्षण के रास्ते में नहीं पाया है, इसलिए मेरे लिए यह समस्या नहीं है यदि आप चाहते हैं कि आप हमेशा POCO ऑब्जेक्ट्स को LINQ से SQL के साथ उपयोग कर सकें

एक और कमी यह है कि जटिल प्रदाता LINQ क्वेरी परीक्षण में सफल हो सकते हैं, लेकिन क्वेरी प्रदाता (खासकर ईएफ 3.5 क्वेरी प्रदाता बेकार) में सीमाओं (या बग) की वजह से उत्पादन में असफल हो जाते हैं। जब आप इस मॉडल का उपयोग नहीं करते हैं, तो आप शायद कस्टम रिपॉज़िटरी क्लासेस लिख रहे हैं जो पूरी तरह से यूनिट टेस्ट संस्करणों से प्रतिस्थापित हैं और आपको अभी भी यूनिट टेस्ट में आपके डेटाबेस से प्रश्नों को जांचने में सक्षम होने की समस्या नहीं होगी। इसके लिए आपको एक लेनदेन द्वारा लिपटे एकीकरण परीक्षणों की आवश्यकता होगी।

इस डिज़ाइन का आखिरी शोर कार्य के यूनिट पर Insert और Delete तरीकों का इस्तेमाल होता है। उन्हें रिपॉजिटरी में ले जाने के दौरान आपको एक विशिष्ट class IRepository<T> : IQueryable<T> इंटरफ़ेस के साथ एक डिजाइन बनाने के लिए मजबूर किया जाएगा, यह आपको अन्य त्रुटियों से रोकता है समाधान में मैं अपने आप का उपयोग करता हूं I भी InsertAll(IEnumerable) और DeleteAll(IEnumerable) विधियां हैं DeleteAll(IEnumerable) हालांकि यह गलत है और context.Delete(context.Messages) तरह कुछ लिखना आसान है। Delete context.Delete(context.Messages)DeleteAll ) ( DeleteAll बजाय Delete का उपयोग नोट करें) यह ठीक संकलन करेगा, क्योंकि हटाए गए object स्वीकार करता object । रिपॉजिटरी पर हटाए गए कार्यों के साथ एक डिज़ाइन इस तरह के कथन को संकलन से रोकेगा, क्योंकि रिपॉजिटरीज टाइप किए गए हैं।

अद्यतनः मैंने इस विषय पर एक ब्लॉग पोस्ट लिखा है जो इस समाधान का और भी विस्तार से वर्णन करता है: अपने LINQ प्रदाता को फिक्स करना ।

आशा है कि ये आपकी मदद करेगा।

यदि कार्य और रिपॉज़िटरी पैटर्न की इकाई के संयोजन में, कुछ लोगों का कहना है कि यूओ को रिपॉजिटरी के बाहर प्रबंधित किया जाना चाहिए ताकि आप दो रिपॉजिटरी (ग्राहक, रिपोजिटरी और ऑर्डररिपॉजिटरी) कहते हैं और उन्हें एक ही यूओडब्ल्यू इंस्टेंस बना सकते हैं ताकि यह सुनिश्चित हो सके कि डीबी में सभी बदलाव परमाणु रूप से किया जा सकता है जब आप अंततः UoW.Complete () कॉल करें।

एक परिपक्व डीडीडी समाधान में, दोनों यूओडब्ल्यू और एक रिपॉजिटरी के लिए आवश्यकता नहीं होनी चाहिए। इसका कारण यह है कि इस तरह की हल की कुल सीमाएं परिभाषित की गई हैं ऐसा एक तरीका है, एक से अधिक रिपॉजिटरी से जुड़े परमाणु परिवर्तन की कोई आवश्यकता नहीं है।

क्या इससे आपके सवाल का जवाब मिलता है?