




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、倉(cāng)儲(chǔ)的實(shí)現(xiàn):深入篇 早在年前的時(shí)候就已經(jīng)在CSAI博客發(fā)表了上一篇文章:倉(cāng)儲(chǔ)的實(shí)現(xiàn):基礎(chǔ)篇??嘤谌找贡疾ㄓ诠ぷ髋c生活之間,一直沒有能夠抽空繼續(xù)探討倉(cāng)儲(chǔ)的實(shí)現(xiàn)細(xì)節(jié),也讓很多關(guān)注EntityFramework和領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的朋友們備感失望。閑話不多說(shuō),現(xiàn)在繼續(xù)考慮,如何讓倉(cāng)儲(chǔ)的操作在相同的事物處理上下文中進(jìn)行。DDD引入倉(cāng)儲(chǔ)模式,其目的之一就是能夠通過(guò)倉(cāng)儲(chǔ)隱藏對(duì)象持久化的技術(shù)細(xì)節(jié),使得領(lǐng)域模型變得更為“純凈”。由此可見,倉(cāng)儲(chǔ)的實(shí)現(xiàn)是需要基礎(chǔ)結(jié)構(gòu)層的組件支持的,表現(xiàn)為對(duì)數(shù)據(jù)庫(kù)的操作。在傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)操作中,事務(wù)處理是一個(gè)很重要的概念,雖然從目前某些大型項(xiàng)目看,事務(wù)處理會(huì)降低效率,但它保證了數(shù)據(jù)的
2、完整性。關(guān)系型數(shù)據(jù)庫(kù)仍然是目前數(shù)據(jù)持久化機(jī)制的主流,事務(wù)處理的實(shí)現(xiàn)還是很有必要的。為了迎合倉(cāng)儲(chǔ)模式,就需要對(duì)經(jīng)典的ObjectContext使用方式作一些調(diào)整。比如,原本我們可以非常簡(jiǎn)單地使用using (EntitiesContainer ec = new EntitiesContainer()語(yǔ)句來(lái)界定LINQ to Entities的操作范圍,并使用ObjectContext的SaveChanges成員方法提交事務(wù),而在引入了倉(cāng)儲(chǔ)的實(shí)現(xiàn)中,就不能繼續(xù)采用這種經(jīng)典的使用方式。這讓EntityFramework看上去變得很奇怪,也很牽強(qiáng),我相信很多網(wǎng)友會(huì)批評(píng)我的做法,因?yàn)槲野褑?wèn)題復(fù)雜化了。其
3、實(shí),這應(yīng)該是關(guān)注點(diǎn)不同罷了。關(guān)注EntityFramework的開發(fā)人員,自然覺得經(jīng)典的調(diào)用方式簡(jiǎn)單明了,而從DDD的角度看呢?只能把關(guān)注點(diǎn)放在倉(cāng)儲(chǔ)上,而把EntityFramework當(dāng)成是倉(cāng)儲(chǔ)的一種技術(shù)選型(當(dāng)然從DDD角度講,我們完全可以不選擇EntityFramework,而去選擇其它技術(shù))。所以本文暫且拋開EntityFramework,繼續(xù)在上文的基礎(chǔ)上,討論倉(cāng)儲(chǔ)的實(shí)現(xiàn)。前面提到,倉(cāng)儲(chǔ)的實(shí)現(xiàn)需要考慮事務(wù)處理,而且根據(jù)DDD的經(jīng)驗(yàn),針對(duì)每一個(gè)聚合根,都需要有個(gè)倉(cāng)儲(chǔ)對(duì)其進(jìn)行持久化以及對(duì)象重新組裝等操作。為此,我的想法是,將倉(cāng)儲(chǔ)操作“界定”在某一個(gè)事務(wù)處理上下文(Context)中,倉(cāng)儲(chǔ)
4、的實(shí)例是由Context獲得的,這有點(diǎn)像EntityFramework中ObjectContext與EntityObject的關(guān)系那樣。由于倉(cāng)儲(chǔ)是來(lái)自于transaction context,所以它知道目前處于哪個(gè)事務(wù)上下文中。我定義的這個(gè)transaction context如下:隱藏行號(hào) 復(fù)制代碼 ?Transaction Contextpublic interface IRepositoryTransactionContext : IDisposable IRepository<TEntity> GetRepository<TEntity&
5、;gt;() where TEntity : EntityObject, IAggregateRoot; void BeginTransaction(); void Commit(); void Rollback();上面第三行代碼定義了一個(gè)接口方法,這個(gè)方法的主要作用就是返回一個(gè)針對(duì)指定聚合根實(shí)體的倉(cāng)儲(chǔ)實(shí)例。剩下那三行代碼就很明顯了,那是標(biāo)準(zhǔn)的transaction操作:?jiǎn)?dòng)事務(wù)、提交事務(wù)以及回滾事務(wù)。在設(shè)計(jì)上,可以根據(jù)需要,選擇合適的技術(shù)來(lái)實(shí)現(xiàn)IRepositoryTransactionContext。我們現(xiàn)在討論的是EntityFramework,所以我將給出EntityFramewor
6、k的具體實(shí)現(xiàn)。當(dāng)然,如果你不選用EntityFramework,而是用NHibernate實(shí)現(xiàn)數(shù)據(jù)持久化,這樣的設(shè)計(jì)同樣能夠使你達(dá)到目的。以下是基于EntityFramework的實(shí)現(xiàn):EdmRepositoryTransactionContext的偽代碼。隱藏行號(hào) 復(fù)制代碼 ?EdmRepositoryTransactionContextinternal class EdmRepositoryTransactionContext : IRepositoryTransactionContext private ObjectContext objContext; private Dictiona
7、ry<Type, object> repositoryCache = new Dictionary<Type, object>(); public EdmRepositoryTransactionContext(ObjectContext objContext) this.objContext = objContext; #region IRepositoryTransactionContext Members public IRepository<TEntity> GetRepository<T
8、Entity>() where TEntity : EntityObject, IAggregateRoot if (repositoryCache.ContainsKey(typeof(TEntity) return (IRepository<TEntity>)repositoryCachetypeof(TEntity); IRepository<TEntity> repository = new EdmRepository<TEntity>(this.objContext); this.rep
9、ositoryCache.Add(typeof(TEntity), repository); return repository; public void BeginTransaction() / We do not need to begin a transaction here because the object context, / which would handle the transaction, was created and injected into the / constructor by Castle Windsor framework. public void Com
10、mit() this.objContext.SaveChanges(); public void Rollback() / We also do not need to perform the rollback operation because / entity framework will handle this for us, just when the execution / point is stepping out of the using scope. #endregion #region IDisposable Members public void Dispose() thi
11、s.repositoryCache.Clear(); this.objContext.Dispose(); #endregionEdmRepositoryTransactionContext被定義為internal,這個(gè)設(shè)計(jì)是合理的,因?yàn)镈omain層是不需要知道事務(wù)上下文的具體實(shí)現(xiàn),它將會(huì)被IoC/DI容器注入到Domain層中(本系列文章采用Castle Windsor框架)。在EdmRepositoryTransactionContext的構(gòu)造函數(shù)中,它需要EntityFramework的ObjectContext對(duì)象來(lái)初始化實(shí)例。同樣,由于IoC/DI的使用,我們?cè)诖a中也是不需要去創(chuàng)
12、建這個(gè)ObjectContext的,交給Castle Windsor就OK了。第13行的GetRepository方法簡(jiǎn)單地采用了Dictionary對(duì)象來(lái)實(shí)現(xiàn)緩存?zhèn)}儲(chǔ)實(shí)例的效果,當(dāng)然這種做法還有待改進(jìn)。EdmRepositoryTransactionContext是不需要BeginTransaction的,我們將方法置空,因?yàn)镋ntityFramework的事務(wù)會(huì)由ObjectContext來(lái)管理,同理,Rollback也被置空。EdmRepository的實(shí)現(xiàn)就比較顯而易見了,請(qǐng)參見上文。此外,我們還可以針對(duì)NHibernate實(shí)現(xiàn)倉(cāng)儲(chǔ)模式,只需要實(shí)現(xiàn)IRepositoryTransact
13、ionContext和IRepository接口即可,比如:隱藏行號(hào) 復(fù)制代碼 ?NHibernateRepositoryTransactionContext實(shí)現(xiàn)internal class NHibernateRepositoryTransactionContext : IRepositoryTransactionContext ITransaction transaction; Dictionary<Type, object> repositoryCache = new Dictionary<Type, object>(); publ
14、ic ISession Session get return DatabaseSessionFactory.Instance.Session; #region IRepositoryTransactionContext Members public IRepository<TEntity> GetRepository<TEntity>() where TEntity : EntityObject, IAggregateRoot if (repositoryCache.ContainsKey(typeof(TEntity) return (
15、IRepository<TEntity>)repositoryCachetypeof(TEntity); IRepository<TEntity> repository = new NHibernateRepository<TEntity>(this.Session); this.repositoryCache.Add(typeof(TEntity), repository); return repository; public void BeginTransaction() transaction = Dat
16、abaseSessionFactory.Instance.Session.BeginTransaction(); public void Commit() transaction.Commit(); public void Rollback() transaction.Rollback(); #endregion #region IDisposable Members public void Dispose() transaction.Dispose(); ISession dbSession = DatabaseSessionFactory.Instance.Session; if (dbS
17、ession != null && dbSession.IsOpen) dbSession.Close(); #endregion隱藏行號(hào) 復(fù)制代碼 ?NHibernateRepository實(shí)現(xiàn)internal class NHibernateRepository<TEntity> : IRepository<TEntity> where TEntity : EntityObject, IAggregateRoot ISession session; public NHibernateRepository
18、(ISession session) this.session = session; #region IRepository<TEntity> Members public void Add(TEntity entity) this.session.Save(entity); public TEntity GetByKey(int id) return (TEntity)this.session.Get(typeof(TEntity), id); public IEnumerable<TEntity> FindBySpecificatio
19、n(Func<TEntity, bool> spec) throw new NotImplementedException(); public void Remove(TEntity entity) this.session.Delete(entity); public void Update(TEntity entity) this.session.SaveOrUpdate(entity); #endregion在NHibernateRepositoryTransactionContext中使用了一個(gè)DatabaseSessionFactory的類,該類主要用于管
20、理NHibernate的Session對(duì)象,具體實(shí)現(xiàn)如下(該實(shí)現(xiàn)已被用于我的Apworks應(yīng)用開發(fā)框架原型中):隱藏行號(hào) 復(fù)制代碼 ?DatabaseSessionFactory實(shí)現(xiàn)/ <summary>/ Represents the factory singleton for database session./ </summary>internal sealed class DatabaseSessionFactory #region Private Static Fields / <summary> /
21、 The singleton instance of the database session factory. / </summary> private static readonly DatabaseSessionFactory databaseSessionFactory = new DatabaseSessionFactory(); #endregion #region Private Fields / <summary> / The session factory instance. / </summary&
22、;gt; private ISessionFactory sessionFactory = null; / <summary> / The session instance. / </summary> private ISession session = null; #endregion #region Constructors / <summary> / Privately constructs the database session factory instance, configures the / N
23、Hibernate framework by using the assemblies listed in the configured spaces(paths) / that are decorated by <see cref="EntityVisibleAttribute"/>. / </summary> private DatabaseSessionFactory() Configuration nhibernateConfig = new Configuration(); nhibernateConfig.
24、Configure(); nhibernateConfig.AddAssembly(typeof(IAggregateRoot).Assembly); sessionFactory = nhibernateConfig.BuildSessionFactory(); #endregion #region Public Properties / <summary> / Gets the singleton instance of the database session factory. / </summary> public static
25、DatabaseSessionFactory Instance get return databaseSessionFactory; / <summary> / Gets the singleton instance of the session. If the session has not been / initialized or opened, it will return a newly opened session from the session factory. / </summary> public ISession S
26、ession get ISession result = session; if (result != null && result.IsOpen) return result; return OpenSession(); #endregion #region Public Methods / <summary> / Always opens a new session from the session factory. / </summary> / <returns>The n
27、ewly opened session.</returns> public ISession OpenSession() this.session = sessionFactory.OpenSession(); return this.session; #endregion簡(jiǎn)單小結(jié)一下。通過(guò)上面的例子可以看到,倉(cāng)儲(chǔ)的實(shí)現(xiàn)是不能依賴于任何技術(shù)細(xì)節(jié)的,因?yàn)轭I(lǐng)域模型并不關(guān)心技術(shù)問(wèn)題。這并不是DDD一書中怎么說(shuō),我們就得怎么做。事實(shí)上的確如此,因?yàn)镈DD的思想,使得我們應(yīng)該把關(guān)注點(diǎn)放在業(yè)務(wù)分析與領(lǐng)域建模上,而倉(cāng)儲(chǔ)實(shí)現(xiàn)的分離正是這一思想的具體表現(xiàn)形式。不管怎么樣,采用其它的手
28、段也罷,我們還是應(yīng)該遵循“將關(guān)注點(diǎn)放在領(lǐng)域”這一宗旨。接下來(lái)看如何在領(lǐng)域?qū)咏Y(jié)合IoC框架使用倉(cāng)儲(chǔ)。仍然以Castle Windsor為例。配置文件如下(超長(zhǎng)部分我用省略號(hào)去掉了): 隱藏行號(hào) 復(fù)制代碼 ?Castle Windsor配置<castle> <components> <!- Object Context for Entity Data Model -> <component id="ObjectContext" service="System.Data.O
29、bjects.ObjectContext, System.Data.Entity, Version=,." type="EasyCommerce.Domain.Model.EntitiesContainer, EasyCommerce.Domain"/> <component id="GeneralRepository" service="EasyCommerce.Domain.IRepository1EasyCommerce.Domain.Model.Customer, ." ty
30、pe="EasyCommerce.Infrastructure.Repositories.EdmRepositories.EdmRepository1EasyCo."> <objContext>$ObjectContext</objContext> </component> <component id="TransactionContext" service="EasyCommerce.Domain.IRepositoryTransa
31、ctionContext, EasyCommerce.Domain." type="EasyCommerce.Infrastructure.Repositories.EdmRepositories.EdmRepositoryTransactionContext, ."> </component> </components></castle>以下是調(diào)用代碼:隱藏行號(hào) 復(fù)制代碼 ?調(diào)用方代碼TestMethodpublic void TestCreateCustomer(
32、) IWindsorContainer container = new WindsorContainer(new XmlInterpreter(); using (IRepositoryTransactionContext tx = container.GetService<IRepositoryTransactionContext>() tx.BeginTransaction(); try Customer customer = Customer.CreateCustomer("daxnet", "12345", new N
33、ame FirstName = "Sunny", LastName = "Chen" , new Address(), new Address(), DateTime.Now.AddYears(-29); IRepository<Customer> customerRepository = tx.GetRepository<Customer>(); customerRepository.Add(customer); tx.Commit(); catch tx.Rollback(); throw; 測(cè)
34、試結(jié)果及數(shù)據(jù)庫(kù)數(shù)據(jù)結(jié)果: 【注意】:在使用NHibernate的倉(cāng)儲(chǔ)實(shí)現(xiàn)時(shí),由于NHibernate的延遲加載特性,需要將實(shí)體的屬性設(shè)置為virtual,以便由NHibernate產(chǎn)生Proxy Class進(jìn)而實(shí)現(xiàn)延遲加載;但是由EntityFramework自動(dòng)生成的源代碼并不會(huì)將實(shí)體屬性設(shè)置為virtual,而采用partial class也無(wú)法解決這個(gè)問(wèn)題。因此需要在代碼生成技術(shù)上做文章。我的做法是,針對(duì)edmx產(chǎn)生一個(gè)基于T4的代碼生成模板,然后修改這個(gè)模板,分別在WritePrimitiveTypeProperty和WriteComplexTypeProperty方法中的適當(dāng)位置加上
35、virtual關(guān)鍵字:隱藏行號(hào) 復(fù)制代碼 ?WritePrimitiveTypeProperty private void WritePrimitiveTypeProperty(EdmProperty primitiveProperty, CodeGenerationTools code) MetadataTools ef = new MetadataTools(this);#> / <summary> / <#=SummaryComment(primitiveProperty)#> / </summary&a
36、mp;gt;<#=LongDescriptionCommentElement(primitiveProperty, 1)#> EdmScalarPropertyAttribute(EntityKeyProperty=<#=code.CreateLiteral(ef.IsKey(primitiveProperty)#>, IsNullable=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty)#>) DataMemberAttribute() &l
37、t;#=code.SpaceAfter(NewModifier(primitiveProperty)#><#=Accessibility.ForProperty(primitiveProperty)#> virtual <#=code.Escape(primitiveProperty.TypeUsage)#> <#=code.Escape(primitiveProperty)#> <#=code.SpaceAfter(Accessibility.ForGetter(primitiveProperty)#>get <#+ if (ef.ClrType(primitiveProperty.TypeUsage) = typeof(byte) #> return StructuralObject.GetValidValue(<#=code
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 科技類產(chǎn)品的網(wǎng)絡(luò)營(yíng)銷與網(wǎng)絡(luò)直播的結(jié)合策略
- 現(xiàn)代居住區(qū)綠建規(guī)劃的生態(tài)效益評(píng)估
- 電動(dòng)車電機(jī)及控制系統(tǒng)維修教程
- 科技與商業(yè)共創(chuàng)未來(lái)新商業(yè)生態(tài)
- 科技研發(fā)過(guò)程中的數(shù)據(jù)質(zhì)量控制
- 知識(shí)產(chǎn)權(quán)教育在高校教育中的推廣
- 2025至2030年中國(guó)荷花牛座筆筒數(shù)據(jù)監(jiān)測(cè)研究報(bào)告
- 科技英語(yǔ)四六級(jí)考試與科技發(fā)展趨勢(shì)
- 2025至2030年中國(guó)茶樹菇粉數(shù)據(jù)監(jiān)測(cè)研究報(bào)告
- 2025至2030年中國(guó)蘆薈滋潤(rùn)潔面乳數(shù)據(jù)監(jiān)測(cè)研究報(bào)告
- 《供熱工程》課件
- 倉(cāng)管員業(yè)務(wù)技能培訓(xùn)
- 安全管理人員七大職責(zé)
- 《國(guó)民經(jīng)濟(jì)行業(yè)分類與代碼》
- 音樂教育國(guó)際化進(jìn)程-洞察分析
- 2025年中鐵特貨物流股份限公司招聘畢業(yè)生52人高頻重點(diǎn)提升(共500題)附帶答案詳解
- 1學(xué)會(huì)尊重-尊重自己(說(shuō)課稿 )-2023-2024學(xué)年道德與法治六年級(jí)下冊(cè)統(tǒng)編版
- 植入式靜脈給藥裝置護(hù)理技術(shù)課件
- 單兵綜合演練
- 疼痛中醫(yī)護(hù)理
- 歐式風(fēng)格的室內(nèi)設(shè)計(jì)
評(píng)論
0/150
提交評(píng)論