FreeSql 以 MIT 開源協(xié)議托管于 github:https://github.com/2881099/FreeSql
主鍵(Primary Key)
class Topic {
[Column(IsPrimary = true)]
public int Id { get; set; }
}
約定:
當沒有指明主鍵時,命名為 id 的字段將成為主鍵;(不區(qū)分大小寫)
當主鍵是 Guid 類型時,插入時會自動創(chuàng)建(有序、不重復(fù))的值,所以不需要自己賦值;(支持分布式)
自增(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; }
}
第三個參數(shù) true 的時候是唯一鍵,false 的時候是普通索引。
數(shù)據(jù)庫類型(DbType)
class Topic {
[Column(DbType = "varchar(128) NOT NULL")]
public string Title { get; set; }
}
可以在類型上指定 NOT NULL,也可以通過 [Column(IsNullable = false)] 設(shè)置;
0.12.8 版本增加了 [Column(StringLength = 128)] 針對字符串的長度設(shè)置;
0.9.12 版本增加了對 MaxLength 特性的解析,上面的 varchar(128) 可改寫成:
class Topic {
[MaxLength(128)]
public string Title { get; set; }
}
當 string 長度 -1 時產(chǎn)生的映射如下:
| MySql | PostgreSQL | SqlServer | Oracle | Sqlite | MsAccess |
|---|---|---|---|---|---|
| text | text | varchar(max) | nvarchar2(4000) | text | longtext |
服務(wù)器時間(ServerTime)
class Topic {
[Column(ServerTime = DateTimeKind.Utc, CanUpdate = false)]
public DateTime CreateTime { get; set; }
[Column(ServerTime = DateTimeKind.Utc)]
public DateTime UpdateTime { get; set; }
}
v0.12.4 使用數(shù)據(jù)庫時間執(zhí)行插入數(shù)據(jù),注意:
1、一但設(shè)置了這個特性,插入的時候設(shè)置屬性值是無效的;
2、插入實體執(zhí)行成功后,實體的值還是 c# 時間;
v1.1 - ServerTime 特性,對 Update 方法時也能生效
其他參考:如果對時間精度要求不高,推薦下面的做法,先計算本地與服務(wù)器時間差距,再使用 Aop 統(tǒng)一處理:
var serverTime = fsql.Select<T>().Limit(1).First(a => DateTime.UtcNow);
var timeOffset = DateTime.UtcNow.Subtract(serverTime); //減去數(shù)據(jù)庫時間
fsql.Aop.AuditValue += new EventHandler<Aop.AuditValueEventArgs>((_, e) =>
{
if (e.Column.Attribute.MapType.NullableTypeOrThis() == typeof(DateTime))
{
if (e.Value == null || (DateTime)e.Value == default(DateTime))
{
e.Value = DateTime.Now.Subtract(timeOffset); //使用本地時區(qū)保存
return;
}
}
});
可空(Nullable)
class Topic {
[Column(IsNullable = false)]
public string Title { get; set; }
}
在不指定 DbType、IsNullable 時,F(xiàn)reeSql 提供默認設(shè)定,如:
- int -> not null(不可為空)
- int? -> null(可空)
一般在使用 string 類型時,才需要手工指明是否可空(string 默認可空);
忽略(Ignore)
class Topic {
[Column(IsIgnore = true)]
public string Title { get; set; }
}
當實體有屬性不需要映射的時候使用,內(nèi)部自動忽略了對象的映射;
當實體內(nèi)的屬性不是可接受的類型時,可以不用指定該特定,如下不必要的指定:
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; }
}
更新整個實體數(shù)據(jù)時,在并發(fā)情況下極容易造成舊數(shù)據(jù)將新的記錄更新。
樂觀鎖的原理,是利用實體某字段,如:long version,更新前先查詢數(shù)據(jù),此時 version 為 1,更新時產(chǎn)生的 SQL 會附加 where version = 1,當修改失敗時(即 Affrows == 0)拋出異常。
每個實體只支持一個樂觀鎖屬性。
適用 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 == 判斷可以使用,無法實現(xiàn) + - * / 等操作;
v0.9.15 版本還可以將值對象映射成 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創(chuàng)建表的字段順序可能不是想要的,通過該特性可以設(shè)置順序。
創(chuàng)建表時指定字段位置,如:[Column(Position = 1],可為負數(shù)即反方向位置;
可插入(CanInsert)、可更新(CanUpdate)
該字段是否可以插入或更新,默認值true,指定為false插入或更新時該字段會被忽略。
當指明了 InsertColumn/UpdateColumns 等方法時,該特性作用可能失效。例如 CanInsert = false 時,又指明了 InsertColumns 該屬性,則仍然會插入。
名稱
FreeSql 默認使用實體的類名,或?qū)傩悦c數(shù)據(jù)庫映射,也可以指定映射的名稱;
指定實體的表名,指定 Name 后,實體類名變化不影響數(shù)據(jù)庫對應(yīng)的表。FreeSql盡量支持了對多數(shù)據(jù)庫或schema支持,不防試試指定表名為:其他數(shù)據(jù)庫.表名,不同數(shù)據(jù)庫的指定方式有差異,這一點以后深入解答。
[Table(Name = "db2.tb_topic111")]
class Topic {
//...
}
注意:盡量不要使用帶點的表名,只有 MySql/Sqlite 對此類表名支持 CodeFirst。但是它不影響 CRUD 功能,使用 [Table(Name = "`sys.config`")] 解決
指定實體的表名,修改為實體類名。指定數(shù)據(jù)庫舊的表名,修改實體命名時,同時設(shè)置此參數(shù)為修改之前的值,CodeFirst才可以正確修改數(shù)據(jù)庫表;否則將視為【創(chuàng)建新表】。
[Table(OldName = "Topic")]
class Topic2 {
//...
}
實體的屬性也有相同的功能,[Column(Name = "xxx")]
禁用遷移
IFreeSql.CodeFirst.IsAutoSyncStructure 可設(shè)置全局【自動遷移結(jié)構(gòu)】功能,也可通過 FreeSqlBuilder.UseAutoSyncStructure(true) 創(chuàng)建 IFreeSql 的時候設(shè)置功能。
當【實體類】對應(yīng)的是數(shù)據(jù)庫【視圖】或者其他時,可通過 [Table(DisableSyncStructure = true)] 禁用指定的實體遷移操作。
[Table(DisableSyncStructure = true)]
class ModelDisableSyncStructure {
[Column(IsPrimary = false)]
public int pkid { get; set; }
}
備注
FreeSql CodeFirst 支持將 c# 代碼內(nèi)的注釋,遷移至數(shù)據(jù)庫的備注。先決條件:
1、實體類所在程序集,需要開啟 xml 文檔功能;
2、xml 文件必須與程序集同目錄,且文件名:xxx.dll -> xxx.xml;
系列文章導(dǎo)航
(三)實體特性