FreeSql.Repository (三)實體特性


歡迎來到《FreeSql.Repository 倉儲模式》系列文檔,本系列文檔專注介紹 【倉儲+工作單元】 的使用方式。完整文檔請前往 wiki 中心:https://github.com/dotnetcore/FreeSql/wiki

提示:FreeSql 可以自動識別 EFCore 實體特性 Key/Required/NotMapped/MaxLength/StringLength/DatabaseGenerated/Table/Column

主鍵(Primary Key)

class Topic
{
    [Column(IsPrimary = true)]
    public int Id { get; set; }
}

約定:

  • 當沒有指明主鍵時,命名為 id 的字段將成為主鍵;(不區分大小寫)

  • 當主鍵是 Guid 類型時,插入時會自動創建(有序、不重復)的值,所以不需要自己賦值;(支持分布式)

自增(Identity)

class Topic
{
    [Column(IsIdentity = true)]
    public int Id { get; set; }
}

約定:

  • 當沒有指明主鍵時,標記自增的成員將成為主鍵;

唯一鍵(Unique Key)、索引(Index)

[Index("uk_phone", "phone", true)]
[Index("uk_group_index", "group,index", true)]
[Index("uk_group_index22", "group, index22 desc", true)]
class AddUniquesInfo
{
    public Guid id { get; set; }
    public string phone { get; set; }

    public string group { get; set; }
    public int index { get; set; }
    public string index22 { get; set; }
}

第三個參數 true 的時候是唯一鍵,false 的時候是普通索引。

數據庫類型(DbType)

class Topic
{
    [Column(DbType = "varchar(128) NOT NULL")]
    public string Title { get; set; }
}

可以在類型上指定 NOT NULL,也可以通過 [Column(IsNullable = false)] 設置;

decimal 指定長度 [Column(DbType = "decimal(10,2)")] 或者 [Column(Precision = 10, Scale = 2)]

string 指定長度 [Column(DbType = "varchar(128)")] 或者 [MaxLength(128)] 或者 [Column(StringLength = 128)],當長度 -1 時產生的映射如下:

MySql PostgreSQL SqlServer Oracle Sqlite Firebird MsAccess 達夢 金倉 神通
text text nvarchar(max) nclob text blob sub_type 1 longtext text text text

注意:MySql [MaxLength(-2)] 或者 [Column(StringLength = -2)] 映射類型 longtext,其他數據庫的映射規則與 -1 相同

服務器時間(ServerTime)

class Topic
{

    [Column(ServerTime = DateTimeKind.Utc, CanUpdate = false)]
    public DateTime CreateTime { get; set; }
    
    [Column(ServerTime = DateTimeKind.Utc)]
    public DateTime UpdateTime { get; set; }
}

使用數據庫時間執行插入數據,注意:

1、一但設置了這個特性,插入的時候設置屬性值是無效的;

2、插入實體執行成功后,實體的值還是 c# 時間;

可空(Nullable)

class Topic
{
    [Column(IsNullable = false)]
    public string Title { get; set; }
}

在不指定 DbType、IsNullable 時,FreeSql 提供默認設定,如:

  • int -> not null(不可為空)
  • int? -> null(可空)

一般在使用 string 類型時,才需要手工指明是否可空(string 默認可空);

忽略(Ignore)

class Topic
{
    [Column(IsIgnore = true)]
    public string Title { get; set; }
}

當實體有屬性不需要映射的時候使用,內部自動忽略了對象的映射;

當實體內的屬性不是可接受的類型時,可以不用指定該特定,如下不必要的指定:

class Topic
{
    [Column(IsIgnore = true)]
    public Topic Parent { get; set; }
}

樂觀鎖(RowVersion)

class Topic
{
    public Guid id { get; set; }
    public string Title { get; set; }

    [Column(IsVersion = true)]
    public int Version { get; set; }
}

更新整個實體數據時,在並發情況下極容易造成舊數據將新的記錄更新。

樂觀鎖的原理,是利用實體某字段,如:long version,更新前先查詢數據,此時 version 為 1,更新時產生的 SQL 會附加 where version = 1,當修改失敗時(即 Affrows == 0)拋出異常(DbUpdateVersionException)。

每個實體只支持一個樂觀鎖屬性。

適用 SetSource 更新,無論使用什么方法更新 version 的值都會增加 1

自定義類型映射(MapType)

class EnumTestMap
{
    public Guid id { get; set; }

    [Column(MapType = typeof(string))]
    public ToStringMapEnum enum_to_string { get; set; }
    [Column(MapType = typeof(string))]
    public ToStringMapEnum? enumnullable_to_string { get; set; }

    [Column(MapType = typeof(int))]
    public ToStringMapEnum enum_to_int { get; set; }
    [Column(MapType = typeof(int?))]
    public ToStringMapEnum? enumnullable_to_int { get; set; }

    [Column(MapType = typeof(string))]
    public BigInteger biginteger_to_string { get; set; }
    [Column(MapType = typeof(string))]
    public BigInteger? bigintegernullable_to_string { get; set; }
}
public enum ToStringMapEnum { 中國人, abc, 香港 }

BigInteger 也可以映射使用,但請注意:僅僅是 CURD 方便, Equals == 判斷可以使用,無法實現 + - * / 等操作;

還可以將值對象映射成 typeof(string),安裝擴展包:

dotnet add package FreeSql.Extensions.JsonMap

fsql.UseJsonMap(); //開啟功能

class TestConfig
{
    public int clicks { get; set; }
    public string title { get; set; }
}
[Table(Name = "sysconfig")]
public class S_SysConfig
{
    [Column(IsPrimary = true)]
    public string Name { get; set; }

    [JsonMap]
    public TestConfig Config { get; set; }
}

字段位置(Position)

適用場景:當實體類繼承時,CodeFirst創建表的字段順序可能不是想要的,通過該特性可以設置順序。

創建表時指定字段位置,如:[Column(Position = 1],可為負數即反方向位置;

可插入(CanInsert)、可更新(CanUpdate)

該字段是否可以插入或更新,默認值true,指定為false插入或更新時該字段會被忽略。

當指明了 InsertColumn/UpdateColumns 等方法時,該特性作用可能失效。例如 CanInsert = false 時,又指明了 InsertColumns 該屬性,則仍然會插入。

自定義插入值(InsertValueSql)

執行 Insert 方法時使用此值,它的語法是 SQL。

注意:如果是 getdate() 這種請可考慮使用 ServerTime,因為它對數據庫間作了適配。

class Type
{
    [Column(InsertValueSql = "'xxx'")]
    public string Name { get; set; }
}

fsql.Insert(new Type()).ExecuteAffrows();
//INSERT INTO `type`(`Name`) VALUES('xxx')

自定義重寫(RewriteSql)、重讀(RereadSql)

寫入時重寫 SQL、讀取時重寫 SQL,適合 geography 類型的讀寫場景。

[Column(
    DbType = "geography", 
    RewriteSql = "geography::STGeomFromText({0}, 4236)", 
    RereadSql = "{0}.STAsText()"
)]
public string geo { get; set; }

//插入:INSERT INTO [ts_geocrud01]([id], [geo]) VALUES(@id_0, geography::STGeomFromText(@geo_0, 4236))

//查詢:SELECT TOP 1 a.[id], a.[geo].STAsText() 
//FROM [ts_geocrud01] a 
//WHERE (a.[id] = 'c7227d5e-0bcf-4b71-8f0f-d69a552fe84e')

名稱

FreeSql 默認使用實體的類名,或屬性名與數據庫映射,也可以指定映射的名稱;

指定實體的表名,指定 Name 后,實體類名變化不影響數據庫對應的表。FreeSql盡量支持了對多數據庫或schema支持,不防試試指定表名為:其他數據庫.表名,不同數據庫的指定方式有差異,這一點以后深入解答。

[Table(Name = "db2.tb_topic111")]
class Topic
{
  //...
}

注意:盡量不要使用帶點的表名,只有 MySql/Sqlite 對此類表名支持 CodeFirst。但是它不影響 CRUD 功能,使用 [Table(Name = "`sys.config`")] 解決

指定實體的表名,修改為實體類名。指定數據庫舊的表名,修改實體命名時,同時設置此參數為修改之前的值,CodeFirst才可以正確修改數據庫表;否則將視為【創建新表】。

[Table(OldName = "Topic")]
class Topic2
{
  //...
}

實體的屬性也有相同的功能,[Column(Name = "xxx")]

禁用遷移

IFreeSql.CodeFirst.IsAutoSyncStructure 可設置全局【自動遷移結構】功能,也可通過 FreeSqlBuilder.UseAutoSyncStructure(true) 創建 IFreeSql 的時候設置功能。

當【實體類】對應的是數據庫【視圖】或者其他時,可通過 [Table(DisableSyncStructure = true)] 禁用指定的實體遷移操作。

[Table(DisableSyncStructure = true)]
class ModelDisableSyncStructure
{
    [Column(IsPrimary = false)]
    public int pkid { get; set; }
}

備注

FreeSql CodeFirst 支持將 c# 代碼內的注釋,遷移至數據庫的備注。先決條件:

1、實體類所在程序集,需要開啟 xml 文檔功能;

2、xml 文件必須與程序集同目錄,且文件名:xxx.dll -> xxx.xml;

系列文章導航


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM