FreeSql 支持功能豐富的表達式函數解析,方便程序員在不了解數據庫函數的情況下編寫代碼。這是 FreeSql 非常特色的功能之一,深入細化函數解析盡量做到滿意,所支持的類型基本都可以使用對應的表達式函數,例如 日期、字符串、IN查詢、數組(PostgreSQL的數組)、字典(PostgreSQL HStore)等等。
IFreeSql fsql = new FreeSql.FreeSqlBuilder().UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10").Build();[Table(Name = "tb_topic")]
class Topic {[Column(IsIdentity = true, IsPrimary = true)]public int Id { get; set; }public int Clicks { get; set; }public int TestTypeInfoGuid { get; set; }public string Title { get; set; }public DateTime CreateTime { get; set; }
}ISelect<Topic> select => fsql.Select<Topic>();
In查詢
var t1 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToSql();
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a
//WHERE (a.`Id` in (1,2,3))
查找今天創建的數據
var t2 = select.Where(a => a.CreateTime.Date == DateTime.Now.Date).ToSql();
SqlServer 下隨機獲取記錄
var t3 = select.OrderBy(a => Guid.NewGuid()).Limit(1).ToSql();
//SELECT top 1 ...
//FROM [tb_topic] a
//ORDER BY newid()
AOP攔截實現自定義解析
IFreeSql 對象有 Aop 成員,那里提供一堆 AOP 攔截的方法。其實有一個事件名稱:ParseExpression。
/// <summary>
/// 可自定義解析表達式
/// </summary>
EventHandler<AopParseExpressionEventArgs> ParseExpression { get; set; }public class AopParseExpressionEventArgs : EventArgs {public AopParseExpressionEventArgs(Expression expression, Func<Expression, string> freeParse) {this.Expression = expression;this.FreeParse = freeParse;}/// <summary>/// 內置解析功能,可輔助您進行解析/// </summary>public Func<Expression, string> FreeParse { get; }/// <summary>/// 需要您解析的表達式/// </summary>public Expression Expression { get; }/// <summary>/// 解析后的內容/// </summary>public string Result { get; set; }
}
FreeParse 是提供給外部的解析工具,它擁有 FreeSql 所有表達式功能,當您自定義解析的過程中遇到特別難處理的,可通過它快速解析出表達式的子部分內容。
表達式函數全覽
表達式 | MySql | SqlServer | PostgreSQL | Oracle | 功能說明 |
---|---|---|---|---|---|
a ? b : c | case when a then b else c end | case when a then b else c end | case when a then b else c end | case when a then b else c end | a成立時取b值,否則取c值 |
a ?? b | ifnull(a, b) | isnull(a, b) | coalesce(a, b) | nvl(a, b) | 當a為null時,取b值 |
數字 + 數字 | a + b | a + b | a + b | a + b | 數字相加 |
數字 + 字符串 | concat(a, b) | cast(a as varchar) + cast(b as varchar) | case(a as varchar)|| b | a|| b | 字符串相加,a或b任意一個為字符串時 |
a - b | a - b | a - b | a - b | a - b | 減 |
a * b | a * b | a * b | a * b | a * b | 乘 |
a / b | a / b | a / b | a / b | a / b | 除 |
a / b | a div b | a / b | a / b | trunc(a / b) | 整除(a,b都為整數) |
a % b | a % b | a % b | a % b | mod(a,b) | 模 |
等等...
數組
表達式 | MySql | SqlServer | PostgreSQL | Oracle | 功能說明 |
---|---|---|---|---|---|
a.Length | - | - | case when a is null then 0 else array_length(a,1) end | - | 數組長度 |
常量數組.Length | - | - | array_length(array[常量數組元素逗號分割],1) | - | 數組長度 |
a.Any() | - | - | case when a is null then 0 else array_length(a,1) end > 0 | - | 數組是否為空 |
常量數組.Contains(b) | b in (常量數組元素逗號分割) | b in (常量數組元素逗號分割) | b in (常量數組元素逗號分割) | b in (常量數組元素逗號分割) | IN查詢 |
a.Contains(b) | - | - | a @> array[b] | - | a數組是否包含b元素 |
a.Concat(b) | - | - | a || b | - | 數組相連 |
a.Count() | - | - | 同 Length | - | 數組長度 |
一個細節證明 FreeSql 匠心制作
通用的 in 查詢 select.Where(a => new []{ 1,2,3 }.Contains(a.xxx))
假設 xxxs 是 pgsql 的數組字段類型,其實會與上面的 in 查詢起沖突,FreeSql 解決了這個矛盾 select.Where(a => a.xxxs.Contains(1))
字典 Dictionary<string, string>
表達式 | MySql | SqlServer | PostgreSQL | Oracle | 功能說明 |
---|---|---|---|---|---|
a.Count | - | - | case when a is null then 0 else array_length(akeys(a),1) end | - | 字典長度 |
a.Keys | - | - | akeys(a) | - | 返回字典所有key數組 |
a.Values | - | - | avals(a) | - | 返回字典所有value數組 |
a.Contains(b) | - | - | a @> b | - | 字典是否包含b |
a.ContainsKey(b) | - | - | a? b | - | 字典是否包含key |
a.Concat(b) | - | - | a || b | - | 字典相連 |
a.Count() | - | - | 同 Count | - | 字典長度 |
JSON JToken/JObject/JArray
表達式 | MySql | SqlServer | PostgreSQL | Oracle | 功能說明 |
---|---|---|---|---|---|
a.Count | - | - | jsonb_array_length(coalesce(a, '[])) | - | json數組類型的長度 |
a.Any() | - | - | jsonb_array_length(coalesce(a, '[])) > 0 | - | json數組類型,是否為空 |
a.Contains(b) | - | - | coalesce(a, '{}') @> b::jsonb | - | json中是否包含b |
a.ContainsKey(b) | - | - | coalesce(a, '{}') ? b | - | json中是否包含鍵b |
a.Concat(b) | - | - | coalesce(a, '{}') | b::jsonb | |
Parse(a) | - | - | a::jsonb | - | 轉化字符串為json類型 |
字符串
表達式 | MySql | SqlServer | PostgreSQL | Oracle | Sqlite |
---|---|---|---|---|---|
string.Empty | '' | '' | '' | '' | |
string.IsNullOrEmpty(a) | (a is null or a = '') | (a is null or a = '') | (a is null or a = '') | (a is null or a = '') | (a is null or a = '') |
string.Concat(a,b,c...) | concat(a, b, c) | a + b + c | a || b || c | a || b || c | a || b || c |
a.CompareTo(b) | strcmp(a, b) | - | case when a = b then 0 when a > b then 1 else -1 end | case when a = b then 0 when a > b then 1 else -1 end | case when a = b then 0 when a > b then 1 else -1 end |
a.Contains('b') | a like '%b%' | a like '%b%' | a ilike'%b%' | a like '%b%' | a like '%b%' |
a.EndsWith('b') | a like '%b' | a like '%b' | a ilike'%b' | a like '%b' | a like '%b' |
a.IndexOf(b) | locate(a, b) - 1 | locate(a, b) - 1 | strpos(a, b) - 1 | instr(a, b, 1, 1) - 1 | instr(a, b) - 1 |
a.Length | char_length(a) | len(a) | char_length(a) | length(a) | length(a) |
a.PadLeft(b, c) | lpad(a, b, c) | - | lpad(a, b, c) | lpad(a, b, c) | lpad(a, b, c) |
a.PadRight(b, c) | rpad(a, b, c) | - | rpad(a, b, c) | rpad(a, b, c) | rpad(a, b, c) |
a.Replace(b, c) | replace(a, b, c) | replace(a, b, c) | replace(a, b, c) | replace(a, b, c) | replace(a, b, c) |
a.StartsWith('b') | a like 'b%' | a like 'b%' | a ilike'b%' | a like 'b%' | a like 'b%' |
a.Substring(b, c) | substr(a, b, c + 1) | substring(a, b, c + 1) | substr(a, b, c + 1) | substr(a, b, c + 1) | substr(a, b, c + 1) |
a.ToLower | lower(a) | lower(a) | lower(a) | lower(a) | lower(a) |
a.ToUpper | upper(a) | upper(a) | upper(a) | upper(a) | upper(a) |
a.Trim | trim(a) | trim(a) | trim(a) | trim(a) | trim(a) |
a.TrimEnd | rtrim(a) | rtrim(a) | rtrim(a) | rtrim(a) | rtrim(a) |
a.TrimStart | ltrim(a) | ltrim(a) | ltrim(a) | ltrim(a) | ltrim(a) |
使用字符串函數可能會出現性能瓶頸,雖然不推薦使用,但是作為功能庫這也是不可缺少的功能之一。
日期
表達式 | MySql | SqlServer | PostgreSQL | Oracle |
---|---|---|---|---|
DateTime.Now | now() | getdate() | current_timestamp | systimestamp |
DateTime.UtcNow | utc_timestamp() | getutcdate() | (current_timestamp at time zone 'UTC') | sys_extract_utc(systimestamp) |
DateTime.Today | curdate | convert(char(10),getdate(),120) | current_date | trunc(systimestamp) |
DateTime.MaxValue | cast('9999/12/31 23:59:59' as datetime) | '9999/12/31 23:59:59' | '9999/12/31 23:59:59'::timestamp | to_timestamp('9999-12-31 23:59:59','YYYY-MM-DD HH24:MI:SS.FF6') |
DateTime.MinValue | cast('0001/1/1 0:00:00' as datetime) | '1753/1/1 0:00:00' | '0001/1/1 0:00:00'::timestamp | to_timestamp('0001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS.FF6') |
DateTime.Compare(a, b) | a - b | a - b | extract(epoch from a::timestamp-b::timestamp) | extract(day from (a-b)) |
DateTime.DaysInMonth(a, b) | dayofmonth(last_day(concat(a, '-', b, '-1'))) | datepart(day, dateadd(day, -1, dateadd(month, 1, cast(a as varchar) + '-' + cast(b as varchar) + '-1'))) | extract(day from (a | |
DateTime.Equals(a, b) | a = b | a = b | a = b | a = b |
DateTime.IsLeapYear(a) | a%4=0 and a%100<>0 or a%400=0 | a%4=0 and a%100<>0 or a%400=0 | a%4=0 and a%100<>0 or a%400=0 | mod(a,4)=0 AND mod(a,100)<>0 OR mod(a,400)=0 |
DateTime.Parse(a) | cast(a as datetime) | cast(a as datetime) | a::timestamp | to_timestamp(a,'YYYY-MM-DD HH24:MI:SS.FF6') |
a.Add(b) | date_add(a, interval b microsecond) | dateadd(millisecond, b / 1000, a) | a::timestamp+(b | |
a.AddDays(b) | date_add(a, interval b day) | dateadd(day, b, a) | a::timestamp+(b | |
a.AddHours(b) | date_add(a, interval b hour) | dateadd(hour, b, a) | a::timestamp+(b | |
a.AddMilliseconds(b) | date_add(a, interval b*1000 microsecond) | dateadd(millisecond, b, a) | a::timestamp+(b | |
a.AddMinutes(b) | date_add(a, interval b minute) | dateadd(minute, b, a) | a::timestamp+(b | |
a.AddMonths(b) | date_add(a, interval b month) | dateadd(month, b, a) | a::timestamp+(b | |
a.AddSeconds(b) | date_add(a, interval b second) | dateadd(second, b, a) | a::timestamp+(b | |
a.AddTicks(b) | date_add(a, interval b/10 microsecond) | dateadd(millisecond, b / 10000, a) | a::timestamp+(b | |
a.AddYears(b) | date_add(a, interval b year) | dateadd(year, b, a) | a::timestamp+(b | |
a.Date | cast(date_format(a, '%Y-%m-%d') as datetime) | convert(char(10),a,120) | a::date | trunc(a) |
a.Day | dayofmonth(a) | datepart(day, a) | extract(day from a::timestamp) | cast(to_char(a,'DD') as number) |
a.DayOfWeek | dayofweek(a) | datepart(weekday, a) - 1 | extract(dow from a::timestamp) | case when to_char(a)='7' then 0 else cast(to_char(a) as number) end |
a.DayOfYear | dayofyear(a) | datepart(dayofyear, a) | extract(doy from a::timestamp) | cast(to_char(a,'DDD') as number) |
a.Hour | hour(a) | datepart(hour, a) | extract(hour from a::timestamp) | cast(to_char(a,'HH24') as number) |
a.Millisecond | floor(microsecond(a) / 1000) | datepart(millisecond, a) | extract(milliseconds from a::timestamp)-extract(second from a::timestamp)*1000 | cast(to_char(a,'FF3') as number) |
a.Minute | minute(a) | datepart(minute, a) | extract(minute from a::timestamp) | cast(to_char(a,'MI') as number) |
a.Month | month(a) | datepart(month, a) | extract(month from a::timestamp) | cast(to_char(a,'FF3') as number) |
a.Second | second(a) | datepart(second, a) | extract(second from a::timestamp) | cast(to_char(a,'SS') as number) |
a.Subtract(b) | timestampdiff(microsecond, b, a) | datediff(millisecond, b, a) * 1000 | (extract(epoch from a::timestamp-b::timestamp)*1000000) | a - b |
a.Ticks | timestampdiff(microsecond, '0001-1-1', a) * 10 | datediff(millisecond, '1970-1-1', a) * 10000 + 621355968000000000 | extract(epoch from a::timestamp)*10000000+621355968000000000 | cast(to_char(a,'FF7') as number) |
a.TimeOfDay | timestampdiff(microsecond, date_format(a, '%Y-%m-%d'), a) | '1970-1-1 ' + convert(varchar, a, 14) | extract(epoch from a::time)*1000000 | a - trunc(a) |
a.Year | year(a) | datepart(year, a) | extract(year from a::timestamp) | 年 |
a.Equals(b) | a = b | a = b | a = b | a = b |
a.CompareTo(b) | a - b | a - b | a - b | a - b |
a.ToString() | date_format(a, '%Y-%m-%d %H:%i:%s.%f') | convert(varchar, a, 121) | to_char(a, 'YYYY-MM-DD HH24:MI:SS.US') | to_char(a,'YYYY-MM-DD HH24:MI:SS.FF6') |
時間
表達式 | MySql(微秒) | SqlServer(秒) | PostgreSQL(微秒) | Oracle(Interval day(9) to second(7)) |
---|---|---|---|---|
TimeSpan.Zero | 0 | 0 | - | 0微秒 |
TimeSpan.MaxValue | 922337203685477580 | 922337203685477580 | - | numtodsinterval(233720368.5477580,'second') |
TimeSpan.MinValue | -922337203685477580 | -922337203685477580 | - | numtodsinterval(-233720368.5477580,'second') |
TimeSpan.Compare(a, b) | a - b | a - b | - | extract(day from (a-b)) |
TimeSpan.Equals(a, b) | a = b | a = b | - | a = b |
TimeSpan.FromDays(a) | a * 1000000 * 60 * 60 * 24 | a * 1000000 * 60 * 60 * 24 | - | numtodsinterval(a*86400,'second') |
TimeSpan.FromHours(a) | a * 1000000 * 60 * 60 | a * 1000000 * 60 * 60 | - | numtodsinterval(a*3600,'second') |
TimeSpan.FromMilliseconds(a) | a * 1000 | a * 1000 | - | numtodsinterval(a/1000,'second') |
TimeSpan.FromMinutes(a) | a * 1000000 * 60 | a * 1000000 * 60 | - | numtodsinterval(a*60,'second') |
TimeSpan.FromSeconds(a) | a * 1000000 | a * 1000000 | - | numtodsinterval(a,'second') |
TimeSpan.FromTicks(a) | a / 10 | a / 10 | - | numtodsinterval(a/10000000,'second') |
a.Add(b) | a + b | a + b | - | a + b |
a.Subtract(b) | a - b | a - b | - | a - b |
a.CompareTo(b) | a - b | a - b | - | extract(day from (a-b)) |
a.Days | a div (1000000 * 60 * 60 * 24) | a div (1000000 * 60 * 60 * 24) | - | extract(day from a) |
a.Hours | a div (1000000 * 60 * 60) mod 24 | a div (1000000 * 60 * 60) mod 24 | - | extract(hour from a) |
a.Milliseconds | a div 1000 mod 1000 | a div 1000 mod 1000 | - | cast(substr(extract(second from a)-floor(extract(second from a)),2,3) as number) |
a.Seconds | a div 1000000 mod 60 | a div 1000000 mod 60 | - | extract(second from a) |
a.Ticks | a * 10 | a * 10 | - | (extract(day from a)86400+extract(hour from a)3600+extract(minute from a)60+extract(second from a))10000000 |
a.TotalDays | a / (1000000 * 60 * 60 * 24) | a / (1000000 * 60 * 60 * 24) | - | extract(day from a) |
a.TotalHours | a / (1000000 * 60 * 60) | a / (1000000 * 60 * 60) | - | (extract(day from a)*24+extract(hour from a)) |
a.TotalMilliseconds | a / 1000 | a / 1000 | - | (extract(day from a)86400+extract(hour from a)3600+extract(minute from a)60+extract(second from a))1000 |
a.TotalMinutes | a / (1000000 * 60) | a / (1000000 * 60) | - | |
a.TotalSeconds | a / 1000000 | a / 1000000 | - | (extract(day from a)86400+extract(hour from a)3600+extract(minute from a)*60+extract(second from a)) |
a.Equals(b) | a = b | a = b | - | a = b |
a.ToString() | cast(a as varchar) | cast(a as varchar) | - | to_char(a) |
數學函數
表達式 | MySql | SqlServer | PostgreSQL | Oracle |
---|---|---|---|---|
Math.Abs(a) | abs(a) | abs(a) | abs(a) | |
Math.Acos(a) | acos(a) | acos(a) | acos(a) | acos(a) |
Math.Asin(a) | asin(a) | asin(a) | asin(a) | asin(a) |
Math.Atan(a) | atan(a) | atan(a) | atan(a) | atan(a) |
Math.Atan2(a, b) | atan2(a, b) | atan2(a, b) | atan2(a, b) | - |
Math.Ceiling(a) | ceiling(a) | ceiling(a) | ceiling(a) | ceil(a) |
Math.Cos(a) | cos(a) | cos(a) | cos(a) | cos(a) |
Math.Exp(a) | exp(a) | exp(a) | exp(a) | exp(a) |
Math.Floor(a) | floor(a) | floor(a) | floor(a) | floor(a) |
Math.Log(a) | log(a) | log(a) | log(a) | log(e,a) |
Math.Log10(a) | log10(a) | log10(a) | log10(a) | log(10,a) |
Math.PI(a) | 3.1415926535897931 | 3.1415926535897931 | 3.1415926535897931 | 3.1415926535897931 |
Math.Pow(a, b) | pow(a, b) | power(a, b) | pow(a, b) | power(a, b) |
Math.Round(a, b) | round(a, b) | round(a, b) | round(a, b) | round(a, b) |
Math.Sign(a) | sign(a) | sign(a) | sign(a) | sign(a) |
Math.Sin(a) | sin(a) | sin(a) | sin(a) | sin(a) |
Math.Sqrt(a) | sqrt(a) | sqrt(a) | sqrt(a) | sqrt(a) |
Math.Tan(a) | tan(a) | tan(a) | tan(a) | tan(a) |
Math.Truncate(a) | truncate(a, 0) | floor(a) | trunc(a, 0) | trunc(a, 0) |
類型轉換
表達式 | MySql | SqlServer | PostgreSQL | Oracle | Sqlite |
---|---|---|---|---|---|
Convert.ToBoolean(a) | bool.Parse(a) | a not in ('0','false') | a not in ('0','false') | a::varchar not in ('0','false','f','no') | - | a not in ('0','false') |
Convert.ToByte(a) | byte.Parse(a) | cast(a as unsigned) | cast(a as tinyint) | a::int2 | cast(a as number) | cast(a as int2) |
Convert.ToChar(a) | substr(cast(a as char),1,1) | substring(cast(a as nvarchar),1,1) | substr(a::char,1,1) | substr(to_char(a),1,1) | substr(cast(a as character),1,1) |
Convert.ToDateTime(a) | DateTime.Parse(a) | cast(a as datetime) | cast(a as datetime) | a::timestamp | to_timestamp(a,'YYYY-MM-DD HH24:MI:SS.FF6') | datetime(a) |
Convert.ToDecimal(a) | decimal.Parse(a) | cast(a as decimal(36,18)) | cast(a as decimal(36,19)) | a::numeric | cast(a as number) | cast(a as decimal(36,18)) |
Convert.ToDouble(a) | double.Parse(a) | cast(a as decimal(32,16)) | cast(a as decimal(32,16)) | a::float8 | cast(a as number) | cast(a as double) |
Convert.ToInt16(a) | short.Parse(a) | cast(a as signed) | cast(a as smallint) | a::int2 | cast(a as number) | cast(a as smallint) |
Convert.ToInt32(a) | int.Parse(a) | cast(a as signed) | cast(a as int) | a::int4 | cast(a as number) | cast(a as smallint) |
Convert.ToInt64(a) | long.Parse(a) | cast(a as signed) | cast(a as bigint) | a::int8 | cast(a as number) | cast(a as smallint) |
Convert.ToSByte(a) | sbyte.Parse(a) | cast(a as signed) | cast(a as tinyint) | a::int2 | cast(a as number) | cast(a as smallint) |
Convert.ToString(a) | cast(a as decimal(14,7)) | cast(a as decimal(14,7)) | a::float4 | to_char(a) | cast(a as character) |
Convert.ToSingle(a) | float.Parse(a) | cast(a as char) | cast(a as nvarchar) | a::varchar | cast(a as number) | cast(a as smallint) |
Convert.ToUInt16(a) | ushort.Parse(a) | cast(a as unsigned) | cast(a as smallint) | a::int2 | cast(a as number) | cast(a as unsigned) |
Convert.ToUInt32(a) | uint.Parse(a) | cast(a as unsigned) | cast(a as int) | a::int4 | cast(a as number) | cast(a as decimal(10,0)) |
Convert.ToUInt64(a) | ulong.Parse(a) | cast(a as unsigned) | cast(a as bigint) | a::int8 | cast(a as number) | cast(a as decimal(21,0)) |
Guid.Parse(a) | substr(cast(a as char),1,36) | cast(a as uniqueidentifier) | a::uuid | substr(to_char(a),1,36) | substr(cast(a as character),1,36) |
Guid.NewGuid() | - | newid() | - | - | - |
new Random().NextDouble() | rand() | rand() | random() | dbms_random.value | random() |
系列文章導航
(一)入門
(二)自動遷移實體
(三)實體特性
(四)實體特性 Fluent Api
(五)插入數據
(六)批量插入數據
(七)插入數據時忽略列
(八)插入數據時指定列
(九)刪除數據
(十)更新數據
(十一)更新數據 Where
(十二)更新數據時指定列
(十三)更新數據時忽略列
(十四)批量更新數據
(十五)查詢數據
(十六)分頁查詢
(十七)聯表查詢
(十八)導航屬性
(十九)多表查詢
(二十)多表查詢 WhereCascade
(二十一)查詢返回數據
(二十二)Dto 映射查詢
(二十三)分組、聚合
(二十四)Linq To Sql 語法使用介紹
(二十五)延時加載
(二十六)貪婪加載 Include、IncludeMany、Dto、ToList
(二十七)將已寫好的 SQL 語句,與實體類映射進行二次查詢
(二十八)事務
(二十九)Lambda 表達式
(三十)讀寫分離
(三十一)分區分表
(三十二)Aop
(三十三)CodeFirst 類型映射
(三十四)CodeFirst 遷移說明
(三十五)CodeFirst 自定義特性