需要有關將ORM和SQL與遺留系統相結合的建議

[英]Need advice on combining ORM and SQL with legacy system


We are in the process of porting a legacy system to .NET, both to clean up architecture but also to take advantage of lots of new possibilities that just aren't easily done in the legacy system.

我們正在將遺留系統移植到.NET,既要清理架構,又要利用許多新的可能性,而這些新的可能性在遺留系統中並不容易。

Note: When reading my post before submitting it I notice that I may have described things a bit too fast in places, ie. glossed over details. If there is anything that is unclear, leave a comment (not an answer) and I'll augment as much as possible

注意:在提交之前閱讀我的帖子時,我注意到我可能在某些地方描述的東西太快了,即。掩飾細節。如果有任何不清楚的地方,請留下評論(不是答案),我會盡可能地增加評論

The legacy system uses a database, and 100% custom written SQL all over the place. This has lead to wide tables (ie. many columns), since code that needs data only retrieves what is necessary for the job.

遺留系統使用數據庫,並在整個地方使用100%自定義編寫的SQL。這導致了寬表(即許多列),因為需要數據的代碼只檢索作業所需的內容。

As part of the port, we introduced an ORM layer which we can use, in addition to custom SQL. The ORM we chose is DevExpress XPO, and one of the features of this has also lead to some problems for us, namely that when we define a ORM class for, say, the Employee table, we have to add properties for all the columns, otherwise it won't retrieve them for us.

作為端口的一部分,除了自定義SQL之外,我們還引入了一個可以使用的ORM層。我們選擇的ORM是DevExpress XPO,其中一個特性也給我們帶來了一些問題,即當我們為Employee表定義一個ORM類時,我們必須為所有列添加屬性,否則它不會為我們檢索它們。

This also means that when we retrieve an Employee, we get all the columns, even if we only need a few.

這也意味着當我們檢索一個Employee時,我們會得到所有列,即使我們只需要一些。

One nice thing about having the ORM is that we can put some property-related logic into the same classes, without having to duplicate it all over the place. For instance, the simple expression to combine first, middle and last name into a "display name" can be put down there, as an example.

使用ORM的一個好處是我們可以將一些與屬性相關的邏輯放入相同的類中,而不必在整個地方復制它。例如,作為示例,可以將用於將名字,中間名和姓氏組合成“顯示名稱”的簡單表達式放在那里。

However, if we write SQL code somewhere, either in a DAL-like construct or, well, wherever, we need to duplicate this expression. This feels wrong and looks like a recipe for bugs and maintenance nightmare.

但是,如果我們在某個地方編寫SQL代碼,無論是在類似DAL的構造中,還是在任何地方,我們都需要復制此表達式。這感覺不對,看起來像是臭蟲和維護噩夢的秘訣。

However, since we have two choices:

但是,因為我們有兩個選擇:

  • ORM, fetches everything, can have logic written once
  • ORM,取一切,可以寫一次邏輯

  • SQL, fetches what we need, need to duplicate logic
  • SQL,提取我們需要的東西,需要復制邏輯

Then we came up with an alternative. Since the ORM objects are code-generated from a dictionary, we decided to generate a set of dumb classes as well. These will have the same number of properties, but won't be tied to the ORM in the same manner. Additionally we added interfaces for all of the objects, also generated, and made both the ORM and the dum objects implement this interface.

然后我們提出了一個替代方案。由於ORM對象是從字典中生成的代碼,因此我們決定生成一組啞類。它們具有相同數量的屬性,但不會以相同方式綁定到ORM。此外,我們為所有對象添加了接口,也生成了接口,並使ORM​​和dum對象都實現了此接口。

This allowed us to move some of this logic out into extension methods tied to the interface. Since the dumb objects carry enough information for us to plug them into our SQL-classes and instead of getting a DataTable back, we can get a List back, with logic available, this looks to be working.

這使我們能夠將一些邏輯移到與接口相關的擴展方法中。由於啞對象攜帶足夠的信息以便我們將它們插入到我們的SQL類中而不是獲取DataTable,我們可以返回一個List,並且邏輯可用,這看起來是有效的。

However, this has lead to another issue. If I want to write a piece of code that only displays or processes employees in the context that I need to know who they are (ie. their identifier in the system), as well as their name (first, middle and last), if I use this dumb object, I have no guarantee by the compiler that the code that calls me is really providing all this stuff.

然而,這導致了另一個問題。如果我想編寫一段代碼,只顯示或處理上下文中的員工,我需要知道他們是誰(即他們在系統中的標識符),以及他們的名字(第一,中間和最后),如果我使用這個愚蠢的對象,編譯器無法保證調用我的代碼真的提供了所有這些東西。

One solution is for us to make the object know which properties have been assigned values, and an attempt to read an unassigned property crashes with an exception. This gives us an opportunity at runtime to catch contract breaches where code is not passing along enough information.

一種解決方案是讓我們使對象知道哪些屬性已賦值,並且嘗試讀取未分配的屬性會因異常而崩潰。這使我們有機會在運行時捕獲代碼未傳遞足夠信息的合同違規。

This also looks clunky to us.

這對我們來說也很笨拙。

So basically what I want advice on is if anyone else has been in, or are in, this situation and any tips or advice you can give.

所以基本上我想要的建議是,如果有其他人進入或處於這種情況,你可以給出任何提示或建議。

We can not, at the present time, break up the tables. The legacy application will still have to exist for a number of years due to the size of the port, and the .NET code is not a in-3-years-release type of project but will be phased in in releases along the way. As such, both the legacy system and the .NET code need to work with the same tables.

目前,我們不能打破這些局面。由於端口的大小,遺留應用程序仍然必須存在多年,並且.NET代碼不是3年內發布類型的項目,但將在發布過程中分階段實施。因此,遺留系統和.NET代碼都需要使用相同的表。

We are also aware that this is not an ideal solution so please refrain from advice like "you shouldn't have done it like this". We are well aware of this :)

我們也知道這不是一個理想的解決方案,所以請不要提出“你不應該這樣做”這樣的建議。我們很清楚這個:)


One thing we've looked into is to create an XML file, or similar, with "contracts". So we could put into this XML file something like this:

我們研究的一件事是使用“合同”創建XML文件或類似文件。所以我們可以將這樣的XML文件放入:

  • There is an Employee class with these 50 properties
  • 有一個包含這50個屬性的Employee類

  • Additionally, we have these 7 variations, for various parts of the program
  • 此外,對於程序的各個部分,我們有這7種變體

  • Additionally, we have these 10 pieces of logic, that each require property X, Y and Z (X, Y and Z varies between those 10)
  • 另外,我們有這10個邏輯,每個都需要屬性X,Y和Z(X,Y和Z在這10個之間變化)

This could allow us to code-generate those 8 classes (full class + 7 smaller variations), and have the generator detect that for variation #3, property X, Y and K is present, and I can then tie in either the code for the logic or the interfaces the logic needs into this class automagically. This would allow us to have a number of different types of employee classes, with varying degrees of property coverage, and have the generator automatically add all logic that would be supported by this class to it.

這可以允許我們代碼生成那8個類(全類+7個較小的變體),並讓生成器檢測到變量#3,屬性X,Y和K存在,然后我可以綁定任何代碼邏輯或邏輯需要的接口自動地進入這個類。這將允許我們擁有許多不同類型的員工類,具有不同程度的屬性覆蓋,並讓生成器自動添加此類支持的所有邏輯。

My code could then say that I need an employee of type IEmployeeWithAddressAndPhoneNumbers.

然后我的代碼可以說我需要一個IEmployeeWithAddressAndPhoneNumbers類型的員工。

This too looks clunky.

這看起來也很笨重。

3 个解决方案

#1


3  

I would suggest that eventually a database refactoring (normalization) is probably in order. You could work on the refactoring and use views to provide the legacy application with an interface to the database consistent with what it expects. That is, for example, break the employe table down in to employee_info, employee_contact_info, employee_assignments, and then provide the legacy application with a view named employee that does a join across these three tables (or maybe a table-based function if the logic is more complex). This would potentially allow you to move ahead with a fully ORM-based solution which is what I would prefer and keep your legacy application happy. I would not proceed with a mixed solution of ORM/direct SQL, although you might be able to augment your ORM by having some entity classes which provide different views of the same data (say a join across a couple of tables for read-only display).

我建議最終數據庫重構(規范化)可能是有序的。您可以使用重構和使用視圖來為遺留應用程序提供與數據庫接口一致的接口。也就是說,例如,將employees表分解為employee_info,employee_contact_info,employee_assignments,然后為遺留應用程序提供名為employee的視圖,該視圖在這三個表之間進行連接(如果邏輯是,則可能是基於表的函數)更復雜)。這可能會讓您繼續使用完全基於ORM的解決方案,這是我希望的並保持您的遺留應用程序的快樂。我不會繼續使用ORM / direct SQL的混合解決方案,盡管您可以通過提供一些實體類來擴充ORM,這些實體類提供相同數據的不同視圖(例如,跨幾個表的連接以進行只讀顯示)。

#2


2  

"We can not, at the present time, break up the tables. The legacy application will still have to exist for a number of years due to the size of the port, and the .NET code is not a in-3-years-release type of project but will be phased in in releases along the way. As such, both the legacy system and the .NET code need to work with the same tables."

“目前我們不能打破這些表格。由於端口的大小,遺留應用程序仍然需要存在多年,並且.NET代碼不是3年 - 發布類型的項目,但將在發布過程中分階段進行。因此,遺留系統和.NET代碼都需要使用相同的表。“

Two words: materialized views.

兩個詞:物化觀點。

You have several ways of "normalizing in place".

你有幾種“正常化”的方法。

  1. Materialized Views, a/k/a indexed views. This is a normalized clone of your source tables.

    物化視圖,a / k / a索引視圖。這是源表的規范化克隆。

  2. Explicit copying from old tables to new tables. "Ick" you say. However, consider that you'll be incrementally removing functionality from the old app. That means that you'll have some functionality in new, normalized tables, and the old tables can be gracefully ignored.

    從舊表到新表的顯式復制。 “Ick”你說。但是,請考慮您將逐步從舊應用程序中刪除功能。這意味着您將在新的規范化表中具有一些功能,並且可以優雅地忽略舊表。

  3. Explicit 2-way synch. This is hard, not not impossible. You normalize via copy from your legacy tables to correctly designed tables. You can -- as a temporary solution -- use Stored Procedures and Triggers to clone transactions into the legacy tables. You can then retire these kludges as your conversion proceeds.

    明確的雙向同步。這很難,並非不是不可能。您可以通過復制從舊表到正確設計的表進行規范化。您可以 - 作為臨時解決方案 - 使用存儲過程和觸發器將事務克隆到舊表中。然后,您可以在轉換過程中淘汰這些kludges。

You'll be happiest to do this in two absolutely distinct schemas. Since the old database probably doesn't have a well-designed schema, your new database will have one or more named schema so that you can maintain some version control over the definitions.

你會很高興在兩個絕對不同的模式中做到這一點。由於舊數據庫可能沒有設計良好的模式,因此新數據庫將具有一個或多個命名模式,以便您可以對定義維護某些版本控制。

#3


0  

Although I haven't used this particular ORM, views can be useful in some cases in providing lighter-weight objects for display and reporting in these types of databases. According to their documentation they do support such a concept: XPView Concepts

雖然我沒有使用過這種特殊的ORM,但在某些情況下,視圖在提供較輕的對象以便在這些類型的數據庫中顯示和報告時非常有用。根據他們的文檔,他們確實支持這樣一個概念:XPView Concepts


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2008/11/16/7125dc470e5c2bcb6f6b4905c1597023.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com