本文章是由機器翻譯。

在練習的模式

永續性模式

Jeremy Miller

內容

對應資料庫物件
現用記錄
資料對應
使用一個存放庫
識別對應
延遲及渴望載入
虛擬 Proxy 模式
取得下一個步驟

開發人員之間常用主題的資料存取。毫無疑問您聽說有充足的特定資料存取技術和持續性的架構上的意見但什麼最佳的方式,使用這些工具,在專案中的嗎?您應該使用哪些準則來選取正確的工具,為您的專案?哪些您前應該知道在概念上有關這些工具您使用?如果您手上有太多的時間,而且想要撰寫您自己的持續性工具 — 您怎麼做知道?

unsurprisingly,所有這些問題的答案為基礎的設計模式的持續性的檢查。

網域模型

當您思考如何將結構並代表商務邏輯,您的系統中可以有一些主要的選擇。在本文中,我主要假設您已選擇網域模型方法組織到實體物件的商務邏輯。

從正式的描述網域模型會是一個物件模型,之網域的合併行為和資料)。

例如,我目前的專案所包含的客戶關係管理。(CRM) 我們有大小寫和使用者和解決方案的實體物件,包含兩個資料,並實作包含資料的商務規則。網域模型的範圍從只是一組非常豐富的模型 jealously 保護背後使用小的介面 (Hardcore 網域驅動開發) 的未經處理資料的資料結構的 anemic 模型中。您的網域模型落這個範圍內的位置是主要複雜商務邏輯,您的系統中確實是的方式常見的報告或資料項目在您的系統需求。

網域模型模式的適當討論已超出本文的範圍中。我強烈建議閱讀的 Martin Fowler 模式,如組織的商業邏輯的主要設計模式的好討論的企業應用程式架構本書的第 2 章。

快速入門之前,先讓我們來檢閱察覺資料庫和資料存取程式碼的角色,您的系統中,兩個主要的方法:

  • 在 keystone 應用程式和一個企業資產的資料庫。資料存取程式碼] 和 [甚至在應用程式或服務程式碼則是只要來連接資料庫外部世界的機制。
  • 中間層和使用者介面或服務層中的商務物件的應用程式並資料庫是一種可靠地保存工作階段 (Session) 之間的商務物件的狀態。

個人,我感覺像第一個,datacentric 觀點來看充分了解.NET 社群中, 讓我要專注於第二個的觀點來看。第二個的觀點中您通常使用實體物件,在中介層。一種或另一個,您可能進行物件 / 關聯式對應 (O / RM) 對應到資料庫資料表,反之亦然,商業項目的資料。您可能會執行它以手動方式但很可能使用某種類型的工具。這些工具會是很棒,和可能儲存大量的開發時間,但有一些問題,您應該要知道,而且很永遠都不錯,以瞭解工具下實際運作的方式。希望,研究本文中的模式可協助在兩個帳戶。

我是一個大的靈活的作法,像測試 driven 的開發、 行為驅動的開發、 精簡的程式設計和連續的設計 proponent。我說,這僅是清除我在我將討論在本文中,模式有非常特定的偏差,並將它可能會顯示。

對應資料庫物件

我已決定我的系統在與實體的中介層物件具有識別碼、 資料和相關的行為的模型。我的商務邏輯都會實,在這些實體物件或使用這些實體物件的網域服務。了,但如何執行您完美地移動資料資料庫和實體物件之間來回嗎?

在一個關聯式的資料庫的情況下您要將欄位和我們的物件的內容移動到資料表和欄位在資料庫中。您可以撰寫此程式碼完全的手,撰寫個別的 INSERT、 UPDATE、 SELECT 和 DELETE SQL 陳述式,但是您會快速地知道您重複自行在程式碼中相當位元。也就是,您要重複指定的物件屬性或欄位中的資料應該儲存至資料庫資料表中特定資料行。

這是其中的物件 / 關聯式對應工具 」 (O / RM) 步驟。當您使用的 O / RM 時,您只要建立資料庫資料表物件屬性的對應並讓 O / RM 工具,瞭解 SQL 陳述式應該是,以及如何將資料從物件移動到 SQL 陳述式時,用來的中繼資料。

讓我們取得具體,,查看 [非常基本的範例。我目前的專案會有如下的位址類別:

public class Address 
{
  public long Id { get; set; }
  public string Address1 { get; set; }
  public string Address2 { get; set; }
  public string City { get; set; }
  public string StateOrProvince { get; set; }
  public string Country { get; set; }
  public string PostalCode { get; set; }
  public string TimeZone { get; set; }
}

我設定之間的對應位址類別,當我需要指定位址類別對應至資料表、 位址,物件將會是如何識別 (主索引鍵),和哪些資料庫資料表的屬性對應。

這個範例中,我使用 Fluent NHibernate 工具對應位址。

我故意執行 longhand 方式顯示所有詳細資料對應。 (在實際的使用方式,我使用 透過組態的慣例 若要排除大部分的 repetitiveness)。 程式碼如下:

public class AddressMap : ClassMap<Address> 
{
  public AddressMap() 
  {
    WithTable("Address");
    UseIdentityForKey(x => x.Id, "id");

    Map(x => x.Address1).TheColumnNameIs("address1");
    Map(x => x.Address2).TheColumnNameIs("address2");
    Map(x => x.City).TheColumnNameIs("city");
    Map(x => x.StateOrProvince).TheColumnNameIs("province_code");
    Map(x => x.Country).TheColumnNameIs("country_name");
    Map(x => x.PostalCode).TheColumnNameIs("postal_code");
  }
}

現在,您對資料庫模型] 所做的物件模型對應,項目對實際執行的對應您大致上有兩個選擇: Active 的記錄或資料對應程式。

現用記錄

當選擇永續性策略,您需要在第一個決策就會是放置負責執行對應的位置。 您有兩個非常不同的選項: 您可以是讓每個實體類別本身負責在的對應或是您可以使用完全不同類別要對應至資料庫。

第一個選項稱為現用的記錄模式: 封裝資料庫存取,物件包裝使用的資料庫資料表或檢視,表中的資料列,並在該資料上加入網域的邏輯。 作用中記錄的方法會放置永續性的方法,直接到實體) 物件。 在這種情況下,位址的類別,就可能有如儲存,更新,和刪除,以及靜態載入方法,以查詢地址物件的資料庫的方法。

現用的記錄模式的一般用法是基本上使強型別的類別包裝在單一資料列,資料庫資料表中。 因此,現用的資料錄類別通常是 (這會變動工具之間) 的資料庫結構的確切的鏡像。 許多 Active 記錄實作會產生實體物件,直接從資料庫結構。

最著名的 Active 記錄實作是 ActiveRecord 工具隨附做為的紅寶石扶手 Web 開發架構的一部分 (這是與 IronRuby 的.NET 程式設計中使用,請參魷 \ cs6 \ f1 \ cf6 \ lang1024 使用者入門使用 IronRuby 及 RSpec,第一部"). 如果我使用 ActiveRecord,我就會先建立名為資料庫中的位址表格。 然後,如果所有我在乎有存取位址的資料和方法來尋找,[儲存],] 和 [插入位址的資料整個位址類別會尋找完全相同這個拼音類別:

class Address < ActiveRecord::Base
end

拼音的實作使用 metaprogramming 來動態建立欄位和查詢的方法符合資料庫資料表名為在執行階段的位址 (pluralized 表單的類別名稱的位址)。

少數的例外現用的記錄模式的.NET 實作通常會使用藉由使用產生程式碼建立.NET 類別的直接資料庫資料表的對應。這個方法的優點是它很容易會讓資料庫和物件模型同步處理。

學習程式設計

精簡的程式設計,教導您 favoring 「 提取 」 設計透過 「 推入 」 的設計,消除浪費的精力,在開發專案中。這表示基礎結構考量像永續性應該只能是設計及建置以滿足商務需求 (視提取) 的需求,而不是建立資料存取層程式碼,您會認為應用程式將會需要的更新版本的 (推入)。

在 [我的經驗,這表示您應該開發系統以累加方式所開發的垂直 — 而不是一次建置系統的一個水平圖層的一次建置一項功能。使用您可以確定這種方式的基礎結構開發不是超過您絕對需要藉由使所有基礎結構程式碼的系統中內建的功能。當您透過使用者介面、 服務或商務邏輯層書寫之前,建置資料存取層或資料庫使用水平時,風險下列:

  • 無法取得適當的意見反應早期的專案共同工作人員因為沒有任何工作功能,來示範
  • 撰寫不必要的基礎結構程式碼,可能不會實際上取得建置的功能
  • 建置錯誤的資料存取程式碼,因為您不瞭解商業需求早期的或需求在之前所建立的其他各層所變更

提取設計也會表示您選擇的資料存取策略應該由應用程式的需求。指定選擇,我可以選擇的系統,我已模組化商務邏輯,在網域模型的 O / RM。報告應用程式,我就不持續性的工具完全的只會使用 SQL 和資料集。我可能會是大部分的資料項目為系統選擇的現用的資料錄的工具。重點,是持續性與資料存取形狀的消費者的需求。

資料對應

將現用的記錄模式可能會是不錯的通常很有用的物件的結構,從資料庫模型而有所不同。您可以要對應多個類別相同的資料庫資料表。您可能必須在舊版的庫結構描述不符合您會想要 Express 某些商務邏輯 (在常發生為我在我最後的數個專案上) 中物件的形狀。

這是我會在其中選擇資料對應工具 」 模式: 一層的物件] 和 [資料庫之間移動資料,同時保持獨立的每個其他和 「 對應工具 」 的對應程式物件類別本身。資料對應工具 」 模式,會移除大部分的實體從類別外部的實體物件持續性的責任。具有資料對應工具 」 模式中,,您存取,查詢,並儲存實體物件,以某種儲存機制 (本文件稍後討論)。

您選擇兩者之間如何?我個人的偏差是非常強向資料對應的解決方案中。另外,Active 記錄是最適合簡單網域邏輯 CRUD-需要大量的應用程式的系統 (建立、 讀取、 更新及刪除,即),和其中網域模型不需要從資料庫結構,許多不同的情況。現用的資料錄可能是更舒適的許多.NET 程式開發小組的因為它表示的工作也就是.NET 小組的更多一般 datacentric 方式,,坦白說,更好支援.NET 本身。我會描述在.NET 空間中大部分的持續性工具,為 Active 記錄工具。

另一方面,資料對應工具 」 是更適當的系統與複雜的網域邏輯的網域模型的形狀將會不同相當從資料庫模型。資料對應程式也會減少您的網域模型類別,從持續性存放區。可能會需要完全重複使用網域模型,以不同的資料庫引擎、 結構描述或甚至不同的儲存機制的情況下很重要。

最重要我為的靈活 practitioner,無法資料對應程式的方法可讓我測試導向開發的效率比的作用中記錄解決方案設計獨立資料庫的物件模型。這是小組要採取的增量的方法,來設計,因為它可讓小組能夠透過物件模型中設計第一次在重整工具,單元測試技術通常更有效,然後穩定的物件模型時,稍後建立資料庫模型的重要的。也更適用導向設計的架構方法,取得的普及,在.NET 社群中,網域資料對應工具 」 模式。

使用一個存放庫

時我已設定身為開發人員在 Windows DNA 天,我本報凡人擔心忘記關閉 ADO 連接物件在我的程式碼中。在 [我的第一個大企業專案,我編碼直接對 ADO。每次我才能要求,或儲存資料庫資料,我必須執行下列:

  1. 尋找某種類型的組態的連接字串
  2. 開啟新的連線到資料庫
  3. 建立命令物件] 或 [在資料錄集物件
  4. 執行 SQL 陳述式或預存的程序
  5. 關閉來釋出資源資料庫連接
  6. 和喔嗯,將一些處理資料存取程式碼周圍的適當錯誤

在第一個問題將是您,absurd 我所撰寫的重複程式碼數量。第二個問題,是我是必須撰寫程式碼正確每一次因為忘記關閉單一的連線無法,可惜的是沒有,磁碟機關鍵性系統離線過重。沒有人想要的程式碼會摺疊的不良的資料庫連線檢疫,壞人但它仍發生次數太頻繁。

在我下的專案中我的同事和我了更聰明的。我們實作會執行所有安裝程式、 分割和錯誤處理程式碼,ADO 連接物件的單一類別。與資料庫無法互動在系統中的任何其他類別,來叫用預存的程序中使用這個中心的類別。我們撰寫更低,程式碼,和更好,我們未能干擾問題引起的忘記關閉資料庫的連線,因為我們必須取得該連線管理程式碼權限僅執行一次。

我的小組所做,是要建立存放庫模式,使用集合的類似介面來存取網域物件的對應層 mediates 網域之間的資料的粗糙的實作。

基本上,存放庫模式只表示您永續性的系統上放置一個外貌,以便您可以 shield 其餘的您的應用程式碼不必知道永續性的運作方式。我目前的專案具有公用的介面看起來像 [圖 1 中使用儲存機制。

[圖 1 儲存機制介面

public interface IRepository 
{
  // Find an entity by its primary key
  // We assume and enforce that every Entity
  // is identified by an "Id" property of 
  // type long
  T Find<T>(long id) where T : Entity;

  // Query for a specific type of Entity
  // with Linq expressions.  More on this later
  IQueryable<T> Query<T>();
  IQueryable<T> Query<T>(Expression<Func<T, bool>> where);

  // Basic operations on an Entity
  void Delete(object target);
  void Save(object target);
  void Insert(object target);

  T[] GetAll<T>();
}

某些類別,在系統中的需要存取的實體物件時, 它只可以使用 IRepository 擷取的實體,由其識別碼或查詢的 LINQ 運算式的實體物件清單。

當我在使用 O / RM 的中使用 NHibernate 程式庫的 IRepository 的具體類別我在提取連接字串,從記憶體,從建置 NHibernate) SessionFactory 的組件中載入對應的定義 (一次,唯一的一次因為它是一個大的效能衝擊),和換行 NHibernate 低階 ISession 介面。 與某些說明,從儲存機制類別,NHibernate 會管理資料庫連接存留週期的問題。

呼。 這是許多在幕後進行的東西。 它是件好事,我已經 swept 與 NHibernate 背後 IRepository 介面直接互動的所有。 我不需要知道的啟動載入 NHibernate 的東西,片載入、 儲存,並且查詢物件。 更好,因為每個類別,取決於資料存取和持續性之抽象 IRepository 介面,我可以在使用 LINQ 物件內部到虛設常式在測試期間的資料庫的 IRepository InMemoryRepository 實作滑動。

識別對應

讓我們來看看常見的案例。 在某種傳送系統的單一邏輯交易,請您有兩個完全不同的類別,各自,工作,但這兩個類別需要在交易期間擷取相同的客戶實體]。 在理想的情況下,要只在單一客戶物件單一交易內的每個邏輯的客戶,讓每個物件正在關閉的一致性的資料。

在永續性 tooling,避免重複邏輯的參考是識別對應模式的工作]。 如所述的 Martin Fowler 的識別碼對應就可確保每個物件取得載入一次導覽中的保留每個載入的物件,並尋找參考它們時,請使用對應物件。

客戶類別,您可能建立一個的識別碼對應, [圖 2 ] 所示的 naïve 實作。 我故意保留從這裡鎖定,為了簡化程式碼的執行緒。 在實際的實作會需要適當的執行緒安全性措施。

[圖 2 識別對應 Customer 類別

public class CustomerRepository 
{
  public IDictionary<long, Customer> _customers = 
    new Dictionary<long, Customer>();

  public Customer FindCustomer(long id) 
  {
    if (_customers.ContainsKey(id)) 
  {
      return _customers[id];
    }

    var customer = findFromDatabase(id);
    _customers.Add(id, customer);

    return customer;
  }

  private Customer findFromDatabase(long id) 
  {
    throw new System.NotImplementedException();
  }
}

在這個範例中,Customer 物件識別其 ID。 當您要求客戶 ID 的執行個體時,CustomerRepository 會先檢查以查看是否它就會有該特定客戶的內部字典。 如果是,則會傳回現有的客戶物件。 否則,CustomerRepository 會從資料庫擷取資料,建置新的客戶的 Customer 物件更新的要求其字典並儲存傳回新的客戶物件。

幸運的是,您通常無法寫入這個程式碼以手動方式,因為任何成熟的持續性的工具應該包含這項功能。 您需要注意這發生在幕後適當範圍的持續性的支援物件。 許多小組將會使用的控制項的工具 (StructureMap、 Windsor、 Ninject,等等),確定單一的 HTTP 要求或執行緒中的所有類別都使用相同的基礎識別對應的反向的生命週期管理功能。 工作模式的單位會為另一種方法在相同的邏輯交易中多個類別管理單一的識別碼對應。

為了說明這個模式多, [圖 3 顯示的範例的識別碼對應的運作方式。 針對目前專案的架構撰寫程式碼。 IRepository 介面,如下列程式碼] 所示的執行個體,包裝單一依次實作識別對應模式的 NHibernate ISession。 當我執行這個測試輸出是:

1 passed, 0 failed, 0 skipped, took 5.86 seconds.

[圖 3] 使用的識別碼對應

[Test]
public void try_out_the_identity_map() 
{
  // All I'm doing here is getting a fully formed "Repository"
  // from an IoC container and letting an IoC tool bootstrap 
  // NHibernate offstage.
  IRepository repository = ObjectFactory.GetInstance<IRepository>();

  // Find the Address object where Id == 1
  var address1 = repository.Find<Address>(1);

  // Find the Address object where Id == 1 from the same Repository
  var address2 = repository.Find<Address>(1);

  // Requesting the same identified Address object (Id == 1) inside the 
  // same Repository / Identity Map should return the exact same
  // object
  address1.ShouldBeTheSameAs(address2);

  // Now, let's create a completely new Repository that has a 
  // totally different Identity Map
  IRepository secondRepository = ObjectFactory.GetInstance<IRepository>();

  // Nothing up my sleeve...
  repository.ShouldNotBeTheSameAs(secondRepository);

  var addressFromSecondRepository = secondRepository.Find<Address>(1);

  // and this is a completely different Address object, even though
  // it's loaded from the same database with the same Id
  addressFromSecondRepository.ShouldNotBeTheSameAs(address1);
}

延遲及渴望載入

其中一個最佳使用持續性工具的優點是能夠載入根物件 (發票,或許),然後直接巡覽至其子系 (InvoiceLineItem) 和相關的物件僅藉由使用父類別的屬性。 不過,遲早要不必擔心您的應用程式的效能。 擷取的整個物件 Graph,您可能需要僅最上層物件大部分時間,或可以不部分物件的圖形不是有效。

這是 [確定]。 在這種情況下,您可以使用在其中您延遲初始化物件之前,它需要之前延遲載入模式。

讓我們將這置於更具體的詞彙。 假設您有名客戶所參考的地址物件的類別:

public class Customer : DomainEntity 
{
  // The "virtual" modifier is important.  Without it,
  // Lazy Loading can't work
  public virtual Address HomeAddress { get; set; }
}

在大部分使用與客戶物件有關的情況下,程式碼永遠不會需要 Customer.HomeAddress 屬性。 在這種情況下您可以設定資料庫對應像載入此 Fluent NHibernate 對應將 Customer.HomeAddress 屬性延遲:

public class CustomerMap : DomainMap<Customer> 
{
  public CustomerMap() 
  {
    // "References" sets up a Many to One
    // relationship from Customer to Address
    References(x => x.HomeAddress)
      .LazyLoad() // This marks the property as "Lazy Loaded"
      .Cascade.All();
  }
}

與開啟的延遲載入,沒有位址資料擷取客戶物件。 不過,只要任何呼叫端會嘗試存取 Customer.HomeAddress 屬性,在第一次,資料將會透明地載入。

注意 virtual Customer.HomeAddress 屬性上的修飾詞。 並非每個永續性工具這,但藉由建立動態子類別會覆寫 HomeAddress 屬性,使其延遲載入的客戶 NHibernate 實作的延遲載入的屬性。 [HomeAddress 屬性必須被標記為虛擬,以允許子類別覆寫屬性。

不用說也有其他的時候,當您在要求的物件,並在您知道您可能會在同一時間需要其子系。 在這種情況下您將可能選擇渴望載入,並有載入在同一時間為父代的子系資料。 有許多持續性的工具將會有某種最佳化 Eager 載入情況下,以擷取單一資料庫的來回往返中資料的階層架構的功能。 如果您需要 Customer.HomeAddress 資料的大部分時間您使用客戶物件,則您會更好執行渴望的載入,以取得客戶及位址資料在同一時間。

這時候我應該重複舊的最大的唯一可靠地調整效能的應用程式的方式使用分析工具的效能的經驗的度量單位。

虛擬 Proxy 模式

延遲載入通常使用實作虛擬的 Proxy 物件看起來就像稍後都載入到實際物件。 讓我們假設網域模型包含名為 CustomerRepresentative 所參考的客戶物件清單的類別。 該類別的一部分如 [圖 4 ] 所示。

[圖 4 CustomerRepresentative

public class CustomerRepresentative 
{
  // I can create a CustomerRepresentative directly
  // and use it with a normal List
  public CustomerRepresentative() 
  {
    Customers = new List<Customer>();
  }

  // Or I can pass an IList into it.
  public CustomerRepresentative(IList<Customer> customers) 
  {
    Customers = customers;
  }

  // It's not best practice to expose a collection
  // like I'm doing here, but it makes the sample
  // code simpler ;-)
  public IList<Customer> Customers { get; set; }
}

當系統使用 CustomerRepresentative 的執行個體,而不需要的客戶清單時,有許多的時候。 在這種情況下您無法直接建構一個 CustomerRepresentative 與虛擬的 Proxy 物件,像是 IList <customer> 看起來的物件,並使用該的虛擬的 Proxy 類別,而不以 CustomerRepresentative 都會進行任何變更。 該虛擬的 Proxy 類別,可能看起來像 [圖 5 。 在 CustomerRepresentative 無法再建立物件的延遲載入如 [圖 6 ] 所示。

[圖 5 CustomerRepresentative 虛擬 Proxy

public class VirtualProxyList<T> : IList<T> 
{
  private readonly Func<IList<T>> _fetcher;
  private IList<T> _innerList;
  private readonly object _locker = new object();

  // One way or another, VirtualProxyList needs to 
  // find the real list.  Let's just cheat and say
  // that something else will pass it a closure
  // that can find the real List
  public VirtualProxyList(Func<IList<T>> fetcher) 
  {
    _fetcher = fetcher;
  }

  // The first call to 
  private IList<T> inner 
  {
    get 
    {
      if (_innerList == null) 
      {
        lock (_locker) 
        {
          if (_innerList == null) 
          {
            _innerList = _fetcher();
          }
        }
      }

      return _innerList;
    }
  }


  IEnumerator IEnumerable.GetEnumerator() 
  {
    return inner.GetEnumerator();
  }

  public IEnumerator<T> GetEnumerator() 
  {
    return inner.GetEnumerator();
  }

  public void Add(T item) 
  {
    inner.Add(item);
  }

  // and the rest of the IList<T> implementation

} 

[圖 6 延遲載入 CustomerRepresentative

public class CustomerRepresentativeRepository 
{
  private readonly ICustomerRepository _customers;

  public CustomerRepresentativeRepository(
      ICustomerRepository customers) 
  {
    _customers = customers;
  }

  // This method will "find" a CustomerRepresentative, and
  // set up the Virtual Proxy for the Customers
  public CustomerRepresentative Find(long id) 
  {
    var representative = findRepresentative(id);
    representative.Customers = 
      new VirtualProxyList<Customer>(() => 
      _customers.GetCustomersForRepresentative(id));

    return representative;
  }
}

類似的本文中之模式的大部分,虛擬 Proxy 不,您可能會以手動的方式寫入但請注意的有您的保存性工具的背景。

取得下一個步驟

當我開始使用 Windows DNA 技術進行程式設計時,我可能花費超過一半的時間使用未經處理的 ADO 程式碼。現在,永續性的程式碼和基礎結構都是我的小組時間在非常小百分比。因此,哪些變更多年來?我們會使用永續性工具 」 和 「 這些的設計模式來消除有太多的 [重複我們用來進行編碼。

這些模式的大部分是來自 Martin Fowler 書籍,企業應用程式架構的模式而定。我強烈建議您閱讀本書,如果您有與撰寫企業應用程式無關。由於長度的限制,以我無法涵蓋一些其他重要的模式類似的工作、 規格和持續性忽略單位。此外,還有很許多方法來使用存放庫模式和設計考量 (單一存放泛型庫與特定,「 縮小 」 儲存機制的類別是否儲存機制應該也公開 [儲存] 方法等)。 我會要研究這些主題,urge,和我可能會寫入要繼續這個討論 「 待處理的文件]。

最後,我想要說比只 Entity Framework 和 LINQ to SQL 的更多.NET 的生態系統。我是滿意 NHibernate 為在資料對應程式,知道相對較少永續性的相關。subSonic 是實常用 Active 記錄作.NET 程式設計的。iBatis.net 棒的現有資料庫,或您要完整時的情況下,可控制撰寫 SQL 陳述式。LLBLGen Pro 會是唯一的查詢功能的一項非常成熟的工具。許多其他工具也可以使用 LINQ 查詢。

您問題或意見寄至mmpatt@Microsoft.com.

Jeremy Miller,C# 的 Microsoft MVP 也是的開放原始碼] StructureMap (作者structuremap.sourceforge。net) 工具與.NET 和即將推出的 StoryTeller (的相依性資料隱碼storyteller.tigris.org) 在.NET 中 supercharged FIT 測試的工具。造訪其部落格,」網底的樹狀結構的開發人員"CodeBetter 網站的一部分。