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