首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

NHibernate 進階映射:Enum 與 Boolean 型別的跨資料庫持久化策略

     編輯:關於.NET

前言

預設情況下,NHibernate 將 enum 對應為整數、bool 對應為資料庫原生型別(SQL Server 為 bit、Oracle 為 NUMBER(1)、MySQL 為 TINYINT)。跨資料庫部署時,型別不一致會導致映射失敗或資料截斷。本文提供三種標準化持久化策略,確保 Domain Model 與資料庫結構解耦。

一、Enum 持久化為字串(整數字串形式)

場景**:資料庫欄位為 VARCHAR,希望儲存「1」、「2」而非「Yes」、「No」,便於 SQL 直讀與報表工具相容。

Domain Model

public enum Status { Yes = 1, No = 2 }

public class Product
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Status Status { get; set; }
    // ...其他屬性
}

映射檔:指定 sql-type 為 varchar

<property name="Status">
    <column name="Status" sql-type="varchar(10)" default="1" not-null="true" />
</property>

原理**:NHibernate 預設 EnumType 會呼叫 Enum.ToString() 序列化為名稱;指定 sql-type="varchar" 後,ADO.NET 參數傳遞時自動轉為字串「1」/「2」,資料庫存儲字串,讀取時再轉回 Enum。

二、Boolean 持久化為 'Y'/'N'(標準 YesNoType)

適用**:Oracle CHAR(1)、PostgreSQL CHAR(1)、通用字元欄位。

<property name="IsDelete" type="NHibernate.Type.YesNoType, NHibernate">
    <column name="IsDelete" sql-type="char(1)" default="N" not-null="true" />
</property>

資料庫實際儲存:'Y' = true,'N' = false。

三、Boolean 持久化為 '1'/'0'(自訂 IUserType)

場景**:資料庫規範要求布林欄位統一用 CHAR(1) 存 '1'/'0',或需相容舊系統。

步驟 1:實作 IUserType

using System;
using System.Data;
using NHibernate;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

public class YesNo10 : IUserType
{
    public bool IsMutable => false;
    public Type ReturnedType => typeof(bool);
    public SqlType[] SqlTypes => new[] { NHibernateUtil.String.SqlType };

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);
        if (obj == null) return null;
        var val = (string)obj;
        if (val != "1" && val != "0")
            throw new Exception($"Expected '1' or '0' but was '{val}'.");
        return val == "1";
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var param = (IDataParameter)cmd.Parameters[index];
        if (value == null) param.Value = DBNull.Value;
        else param.Value = (bool)value ? "1" : "0";
    }

    public object DeepCopy(object value) => value;
    public object Replace(object original, object target, object owner) => original;
    public object Assemble(object cached, object owner) => cached;
    public object Disassemble(object value) => value;

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.Equals(y);
    }

    public int GetHashCode(object x) => x == null ? typeof(bool).GetHashCode() + 473 : x.GetHashCode();
}

步驟 2:映射檔引用自訂型別(格式:完整類型名, 組件名)

<property name="IsDelete" type="Com.Andyshi.NH3.Domain.YesNo10, Com.Andyshi.NH3">
    <column name="IsDelete" sql-type="char(1)" default="0" not-null="true" />
</property>

策略選擇速查表

目標資料庫/規範Enum 策略Boolean 策略
SQL Server (bit)預設 int預設 bit
Oracle (CHAR(1))sql-type="varchar(10)"YesNoType ('Y'/'N') 或 YesNo10 ('1'/'0')
MySQL (TINYINT)預設 int預設 tinyint(1)
跨資料庫統一規範統一 varchar(10) 存數字字串統一 char(1) 存 '1'/'0' (YesNo10)

最佳實踐建議

  1. 集中管理自訂型別:建立 NHibernate.Types 專案,所有 IUserType 實作置於此,映射檔統一引用。
  2. 使用 Convention (Fluent NHibernate / NHibernate.Mapping.Attributes):以慣例取代配置,自動套用 YesNo10 至所有 bool 屬性。
  3. 資料庫遷移腳本同步更新**:修改映射策略時,務必同步產生 ALTER TABLE ... ALTER COLUMN 腳本,避免型別不匹配導致部署失敗。

本文出自「突破中的IT架構師」博客,請保留出處:https://virusswb.blog.51cto.com/115214/1229651

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved