歡迎來到《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;