
問題解答傳Entity vs 傳ObjectId先把你的場景前提說清楚你現(xiàn)在這套XDataParserNJ全部傳入Entity entity前提調(diào)用方必須已經(jīng)在打開的事務范圍內(nèi)拿到這個EntityOpenMode.ForRead事務沒有釋放實體對象沒有Dispose。1、傳Entity方案的優(yōu)點你說的少一層事務打開確實成立上層已經(jīng)打開事務拿到實體直接把實體引用向下傳遞工具內(nèi)部不需要再new Transaction、不需要GetObject代碼簡潔減少重復寫事務樣板代碼讀取XData本身只需要ForRead不會修改實體讀取場景下性能、內(nèi)存都沒問題你現(xiàn)在的讀取邏輯只讀XData不修改實體這套讀取代碼本身設計是可以這么寫的能正常工作。2、致命風險點必須重視坑都出在調(diào)用方不是Parser內(nèi)部風險不在XDataParserNJ內(nèi)部風險在調(diào)用者忘記約束傳入已經(jīng)失效的Entity。什么情況下Entity會失效、直接崩潰事務tr.Commit()/tr.Abort()之后事務銷毀你還拿著外面的Entity引用再調(diào)用GetDictionary(entity)直接報ObjectDisposedExceptionusing事務塊結束Entity超出生命周期對象已經(jīng)被回收多線程場景、CAD事件回調(diào)把Entity存到類成員變量隔一段時間再去調(diào)用讀取。現(xiàn)象調(diào)試的時候在同一個事務內(nèi)調(diào)用一切正常代碼跑一段時間偶現(xiàn)崩潰很難復現(xiàn)。傳ObjectId的優(yōu)勢在哪里//輸入ObjectId工具內(nèi)部自己開事務讀取 Dictionarystring,string GetDictionary(ObjectId entId)工具函數(shù)內(nèi)部自己負責GetObject using(transaction)調(diào)用方無論怎么傳都不會傳進來一個已經(jīng)銷毀的實體調(diào)用方不用關心當前是否處在事務里隨時拿Id就可以調(diào)用魯棒性更高代價就是內(nèi)部每次會新建一次讀取事務僅僅ForRead開銷很小管網(wǎng)幾十上百實體完全無壓力。3、分場景給結論?【讀取場景你現(xiàn)在XDataParserNJ這套讀取】只讀取XData不修改實體可以繼續(xù)使用Entity入?yún)⒌且獜娭萍s定調(diào)用契約契約必須寫在注釋上/// summary /// 獲取實體XData鍵值字典 /// 【調(diào)用約束】傳入的entity必須來自當前未提交/未釋放的事務OpenMode.ForRead事務不能提前Dispose /// 禁止把Entity保存到成員變量、跨事務調(diào)用跨事務請使用ObjectId版本重載 /// /summary /// param nameentity事務中打開的實體/param /// returns/returns public override Dictionarystring, string GetDictionary(Entity entity)適合上層已經(jīng)在事務內(nèi)部循環(huán)遍歷實體直接向下傳遞實體追求少寫事務代碼。??【寫入XData場景強烈不建議傳Entity】寫入XData需要OpenMode.ForWrite如果你上層傳進來一個ForRead打開的Entity工具內(nèi)部沒辦法把它升級成寫你要么上層必須ForWrite打開要么工具內(nèi)部要重新GetObject那實體參數(shù)就失去意義。寫入XData建議全部使用ObjectId作為入?yún)⒐ぞ邇?nèi)部自己開啟事務ForWrite打開實體控制完整生命周期。?折中方案推薦工程上的寫法兩套重載都實現(xiàn)現(xiàn)有版本傳入Entity僅限同事務內(nèi)調(diào)用用于循環(huán)批量讀取增加一個ObjectId對外公開入口內(nèi)部自己開事務拿到Entity再調(diào)用現(xiàn)有邏輯。public Dictionarystring, string GetDictionary(ObjectId entityId) { using(var tr entityId.Database.TransactionManager.StartTransaction()) { var ent tr.GetObject(entityId, OpenMode.ForRead) as Entity; var dict GetDictionary(ent); tr.Commit(); return dict; } }這樣循環(huán)批量讀取的時候上層拿到Entity直接調(diào)用第一個重載省事務其他零散場景手里只有ObjectId直接調(diào)用Id版本不用關心事務4、回到你現(xiàn)在的XDataParserNJ現(xiàn)狀總結當前讀取邏輯功能沒問題是可行的設計隱患不在Parser內(nèi)部在于調(diào)用方違反契約傳入已經(jīng)釋放的Entity寫XData那一側一定不要照搬Entity入?yún)?yōu)先ObjectId建議增加ObjectId的重載做對外安全入口防止外部調(diào)用者踩坑。順帶確認你的XData寫入規(guī)則對齊讀取代碼你的讀取規(guī)則XData AppName1001(應用程序名)組碼1000存儲字符串格式key:value分隔符來自PipeFieldConfig.Instance.FieldDelimiter一個1000組碼存一組key:value多個字段就多條1000。寫入的時候要嚴格對齊先清除舊的該AppName下全部XData再批量追加一組一組1000的key:value字符串不要拼接成一個大字符串塞單個1000否則讀取解析會出錯。接下來我們就基于這套規(guī)則寫XData寫入工具輸入ObjectId Dictionarystring,string寫入這套格式的XData。需要我直接輸出寫入工具代碼嗎