C#提供運算符重載功能,但這功能使用的場合並不多,相信很多C#開發人員雖然了解到有這一功能,但相信用到的比較少.為什麼要自己重載運算符來生成SQL而不去用Linq?其目的也是非常簡單的使用簡單和靈活。先來看一下有多少運算符可以重載:+, -, *, /, %, &, |, ^, <<, >>==, !=, <, >, <=, >=
看上去還是挺多的,應該能滿SQL對應的需要,首先整理出一個對應關系
c# SQL
== =
!= <>
> >
>= >=
< <
<= <=
& and
| or
總得來說基礎的已經差不多了,但決少like,in等,這些可以使用函數或一技巧上的轉換實現.
既然實現運算符重載,那當然就要重建一個對象做他基礎實現,其作用就是類似於SQL中的字段.
public class FieldInfo
{
public FieldInfo(string table, string name)
{
DBContext.Init();
mTable = table;
mName = name;
}
private string mTable;
public string Table
{
get
{
return mTable;
}
}
private string mName;
public string Name
{
get
{
return mName;
}
}
}
表達一個字段的類型以上描述就足夠了,有所在的表名和字段名.在實現運算符重載前還是把基礎功能用函數實現,運算符重載方法簡單調用就OK了.
public Expression Eq(object value)
{
string p = Expression.GetParamName();
Expression exp = new Expression();
exp.SqlText.Append(string.Format(" {0}=@{1} ",Name,p));
exp.Parameters.Add(new Command.Parameter{ Name=p,
Value=Mappings.PropertyCastAttribute.CastValue(Table,Name, value)});
return exp;
}
public Expression LtEq(object value)
{
string p = Expression.GetParamName();
Expression exp = new Expression();
exp.SqlText.Append(string.Format(" {0}<=@{1} ", Name, p));
exp.Parameters.Add(new Command.Parameter { Name = p,
Value = Mappings.PropertyCastAttribute.CastValue(Table, Name, value)
});
return exp;
}
public Expression Lt(object value)
{
string p = Expression.GetParamName();
Expression exp = new Expression();
exp.SqlText.Append(string.Format(" {0}<@{1} ", Name, p));
exp.Parameters.Add(new Command.Parameter { Name = p,
Value = Mappings.PropertyCastAttribute.CastValue(Table, Name, value)
});
return exp;
}
大體上描述幾個方法實現就行了,對於其他實現原理一樣.下面開始運算重載部分
public static Expression operator ==(FieldInfo field, object value)
{
if (value == null)
return field.IsNull();
if (value is System.Collections.IEnumerable && value.GetType() !=typeof(string))
return field.In((System.Collections.IEnumerable)value);
return field.Eq(value);
}
public static Expression operator !=(FieldInfo field, object value)
{
if (value == null)
return field.IsNotNull();
if (value is System.Collections.IEnumerable && value.GetType() != typeof(string))
return field.NotIn((System.Collections.IEnumerable)value);
return field.NotEq(value);
}
public static Expression operator >(FieldInfo field, object value)
{
return field.Gt(value);
}
public static Expression operator >=(FieldInfo field, object value)
{
return field.GtEq(value);
}
public static Expression operator <(FieldInfo field, object value)
{
return field.Lt(value);
}
public static Expression operator <=(FieldInfo field, object value)
{
return field.LtEq(value);
}
到這裡工作算是完成了,不過好象少了點什麼東西似的...似乎沒有實現&和|;因為這兩個運算不是比較運算符所以不是FieldInfo對象實現的.以上代碼中每個比較運算都返回了一個Expression對象,那&和|自然就由它來實現了
public static Expression operator &(Expression exp1, Expression exp2)
{
if (exp1 == null || exp1.SqlText.Length == 0)
return exp2;
if (exp2 == null || exp2.SqlText.Length == 0)
return exp1;
Expression exp = new Expression();
exp.SqlText.Append("(");
exp.SqlText.Append(exp1.ToString());
exp.SqlText.Append(")");
exp.Parameters.AddRange(exp1.Parameters);
exp.SqlText.Append(" and (");
exp.SqlText.Append(exp2.SqlText.ToString());
exp.SqlText.Append(")");
exp.Parameters.AddRange(exp2.Parameters);
return exp;
}
public static Expression operator |(Expression exp1, Expression exp2)
{
if (exp1 == null || exp1.SqlText.Length == 0)
return exp2;
if (exp2 == null || exp2.SqlText.Length == 0)
return exp1;
Expression exp = new Expression();
exp.SqlText.Append("(");
exp.SqlText.Append(exp1.ToString());
exp.SqlText.Append(")");
exp.Parameters.AddRange(exp1.Parameters);
exp.SqlText.Append(" or (");
exp.SqlText.Append(exp2.SqlText.ToString());
exp.SqlText.Append(")");
exp.Parameters.AddRange(exp2.Parameters);
return exp;
}
對於以上完整代碼可以從https://smarkdata.svn.codeplex.com/svn/Smark/Smark.Data/Smark.Data/Expression.cs獲取
實現代碼的都完成的,那看一下分別在不同查詢的情況下是什麼效果:
sql:
select * from customer where region='UK'
c#
(Customer.Region=='UK').List<Customer>()
sql:
select * from Orders where OrderDate>'1998-7-8' and OrderDate <' 1998-8-8'
c#
(Order.OrderDate >"1998-7-8" & Order.OrderDate<"1998-8-8").List<Orders>()
sql:
select * from Orders where CustomerID in('2','5','6')
c#
(Orders.CustomerID ==new []{"2","5","6"}).List<Orders>();
sql:
select * from Orders where CustomerID in(select customerid from customer where region='UK')
c#
(Orders.CustomerID==Customer.CustomerID[Customer.Region=="UK"]).List<Orders>();
從以上代碼可以看出由於自己重載所以自由度很高,對於==這個運算符可以代替很多SQL的比較操作如:=,in,in(select)等,當然還可以發揮編寫者了想象力.
由於是自定義編寫實現,那條件動態組合當然要比Linq所靈活很多:
Expression exp;
if(a)
exp &=order.id=="a";
if(b)
exp &= order.customerid==customer.customerid[customer.region=="b"]
作者:smark