使用者自訂欄位

2013 年 7 月 23 日

軟體系統中的一個常見功能是允許使用者在資料結構中定義自己的欄位。考慮一個通訊錄 - 有許多事情你可能想要新增。隨著每天都有新的社群網路出現,使用者可能想要為他們的聯絡人新增一個 Bunglr ID 的新欄位。

對於記憶體中的目的,通常最好的方法是允許類別包含一個雜湊映射欄位,用於使用者定義的欄位(肯特·貝克稱之為「變數狀態」的模式)。

# ruby
class Contact
  attr_accessor :firstname, :lastname

  def initialize
    @data = {}
  end

  def [] arg
    return @data[arg]
  end
  def []= key, value
    @data[key] = value
  end
end

aCustomer = Contact.new
aCustomer.firstname = "Martin"
aCustomer[:bunglrId] = 'fowl'

透過這樣的設定,你可以為你的使用者介面新增功能,允許使用者將新欄位附加到物件。如果你想要常見的使用者定義欄位,你可以使用類別變數來保留雜湊映射的常見金鑰清單。有些尷尬的是,常規欄位與使用者定義欄位的存取方式不同,但根據你的語言,甚至可以克服這一點。如果你的語言支援 動態接收,那麼你可以使用它來使用常規欄位存取來存取雜湊映射。

類別聯絡人...

  def method_missing(meth, *args)
    if @data.has_key? meth
      return @data[meth]
    else
      super
    end
  end

通常最棘手的部分是如何找出如何保留這個。如果你正在使用無模式資料庫,那麼通常很簡單 - 你只需將使用者定義的金鑰新增到你的應用程式定義的金鑰中即可。棘手的部分來自具有 儲存模式 的資料庫,特別是關係資料庫。

通常最好的選項是使用 序列化 LOB,基本上建立一個大型文字欄位,你可以在其中將使用者定義的欄位儲存為 JSON 或 XML 文件。現今許多資料庫都提供對此方法相當不錯的支援,包括根據 LOB 中的資料結構進行索引和查詢的支援。然而,此類支援(如果有的話)通常比使用欄位更為尷尬。 [1]

另一條路徑是使用某種屬性表。表格可能看起來像這樣。

CREATE TABLE ContactAttributes (
  contactId   INTEGER, 
  attribute   TEXT, 
  value       TEXT, 
  PRIMARY KEY (contactId, attribute))

同樣地,查詢和索引很尷尬。查詢可能涉及相當多的額外聯結,可能會變得相當混亂。

預先定義的客製化欄位提供另一個系統。在這裡,你可以使用像 custom_field_1(以及可能 custom_field_1_name)這樣的欄位設定模式。你僅限於每個執行個體預先定義的客製化欄位數量。索引和查詢一如往常地很尷尬。

當使用屬性表格或預先定義的客製欄位時,您可以選擇為不同的 SQL 資料類型設定不同的欄位。因此,預先定義的欄位可能是 integer_1, integer_2, text_1…,或屬性表格可能有多個值欄位 (text_value, integer_value)。

動態架構是一種經常被忽略的方法。為此,您會設定好一切,以便當有人新增欄位時,您可以使用 alter table 陳述式將該欄位新增至表格。我們的 Mingle 團隊執行此操作,並且對於其運作方式感到滿意。 [2] 新欄位可以索引和查詢,就像應用程式定義的欄位一樣。這表示所有執行個體都會取得所有欄位,因此如果您在執行個體之間取得大量的差異,這將不太方便。

您的持久性架構選擇將受到您用於關聯性對應的內容影響。使用者定義的欄位並非關聯性對應問題中最常使用的部分,因此在不同的關聯性對應函式庫中,支援會有所不同。

使用者定義的欄位與非均勻類型 [3] 是類似的問題。這兩個問題都會導致需要更彈性的架構,或確實需要完全無架構的方法 (儘管請記住 無架構並不表示您沒有架構)。如果您有非均勻類型,且不會在使用者的要求下變更,則其中一種面向繼承的模式可能會有意義。(單一表格繼承類別表格繼承具體表格繼承。)

備註

1: Bret Taylor 描述一種架構,用於透過為每個可索引欄位建立個別索引表格來索引此類架構中的欄位。

2: Mingle 的方法實際上比僅將欄位新增至現有表格更複雜。Mingle 的中央記錄類型是卡片 (代表故事、任務等)。卡片上的欄位因專案而異,而且您可以在同一個資料庫中擁有許多專案。因此,Mingle 沒有使用單一卡片表格,而是為每個專案的卡片建立一個新表格。然後,它會根據使用者的需求動態地將欄位新增至此表格。

3: 非均勻類型是指執行個體使用少數且非常不同的欄位選取的類型。有時這些稱為稀疏表格,因為如果您檢視整個表格,每列只會使用大量欄位中的少數欄位。非均勻類型與使用者定義的欄位之間的差異在於,非均勻類型具有開發人員已知的全部潛在欄位,而使用者定義的欄位允許建立開發人員永遠不會知道的欄位。