所有設計復雜的ORM都是浮雲


很久沒有寫文章了。

一直很忙,不是很有時間整理。

今天主要是來吐槽下那些設計很復雜的ORM的。

項目做的越多,越覺得ORM這個東西設計的太復雜實在是沒什么意義。

比較推崇Dapper這樣比較簡單,效率比較給力的是ORM。

他其實什么都沒做,只是把數據庫的字段映射到對象的字段上,我覺得就這一個功能就OK了。

其他的功能對ORM來說基本上都是沒什么用的。

待我慢慢道來!

 

一行只寫一句話,是因為寫C#代碼習慣了,不是詩, 不要誤會!

 

你說你的ORM支持全數據庫。

啊哈,一般來說項目開始的時候數據庫就已經選好型了。

只要你不是非常二逼或傻逼,選一些非常不入流,而且能力不是很強的數據庫。

后面基本上是不會更換數據庫的。

所以,為毛要支持啊。

在通用和性能之間,有一條溝,你要么站在溝左邊,要么在溝右邊。

站中間,哈哈,掉下去了。

你說你開始的沒想到后面會有這么大的數據。

啊哈,你的架構師不給力么!

好,不是架構師的問題。

窮逼的,牛逼的MYSQL。

苦逼的,牛逼的MSSQL。

二逼的,牛逼的ORACLE。

傻逼的,牛逼的DB2。

大家一開始都是在考慮當前的需求。

並且稍稍的考慮的下未來幾年的可能,或者沒有考慮。

所以不能怪架構師,誰讓甲方剛開始只給那么點錢。

好了,時間越來越久,數據庫越來越慢。

腫么辦?

升級數據庫哈!

這不,你看還是有換數據庫的需求的吧。

啊哈,怎么說呢?

總覺得換一種數據庫就能解決問題?

世界上著名的數據庫就那幾種!

在一些特定的領域

ORACLE比MSSQL牛逼多少?

MSSQL比MYSQL牛逼多少?

牛逼不了多少的哈

沒見上邊么,每一種數據庫都有牛逼的人在用么

你覺得你的數據庫不行!

你調優了么?你優化業務了么?你還在用奔騰時代的機器來挑戰這大數據時代么?

所以,換數據庫是最最壞的打算。

而且你就算想換,現在的ORM也解決不了100%的問題啊。

數據遷徙,要專業工具!數據庫管理,要專業人員!

所以你想用一套東西來解決所有問題。

上帝尚不能造一塊自己搬不起的石頭,何況是你!

 

 

你說用了ORM,媽媽再也不用擔心的我SQL了!

啊哈,怎么吐槽你呢?

好的開發人員有四個技術基本功,知道么!

開發語言,SQL,抽象能力和自嘲!

不會任何一樣,你都不是一個好的開發。

會拿開發語言寫函數,會自定義對象,會拿語言表述一套完整的業務流程。

不錯!很不錯!

但是你還差三樣!

你起碼要會寫函數吧!知道怎么拿SQL自定義類型吧(對不起,主流數據庫都支持的哈)!會用存儲過程來表述一套完整的流程吧!

但是你差兩樣!

你說你已經寫了一套ORM可以通吃所有數據庫啦!

呵呵,不錯!來,學着星爺的腔調來一句,“其實我是一個程序員”!

哦也,你功德圓滿,隨你師父和大師兄,三師兄以及小白馬回大唐去吧!

什么!

你說不要把業務放到數據庫里面,換數據庫不方便!

騷年,從頭看看。

好,你已經看過了,但是你還是覺得放到數據庫里不放心,你還是可能換數據庫!

各種主流數據庫的表主流的字段類型基本可以通用哈。

各種主流數據庫的函數和存儲過程的調用都差不多哈。

各種主流數據庫的你有的基本大家都有哈。

只要不使用太特殊的東西,換個庫神馬的,小case啦。

你說你用了!

你說你用了ORACLE的包,Java Source!你想換!

你說你用了MSSQL的表變量,C# UDT,花了好幾千大洋裝上了R2!你想換!

你說你用了MYSQL的枚舉,對InnoDB疼愛有加!但是你想換!

.......

少年,為什么要放棄治療!

都這樣了,都滄海桑田了,你還是好好珍惜你們的感情吧。

換啥!換一種思維來解決問題吧,坑挖的越來越深的時候,就該想想是不是改往寬挖挖了!

就算非得換數據庫,你真的以為,自定義的那套別扭的語法能為你新的數據庫帶來很好的性能么?

說我了解的,只說最簡單的,而且通用的語法層面!

CTE這么好用的東西,你來,用ORM生成一條試試看。

MERGE這么好用的東西,你來,用ORM生成一條試試看。

SQL BLOCK這么好用的東西,你來,用ORM生成一條試試看。

(注:SQL BLOCK是ORACLE的叫法,MSSQL原生支持所以沒有太V587的名字)

為什么非要各種數據庫的方言上做痛苦的掙扎?

你確實練就了一身無敵的抽象能力,你確實碉堡了!

但是,呵呵,別忘了那句,“我是程序員,你叫我序員就好了”,生亦何歡死亦何苦哈,何必非要和自己過不去呢,是不!

 

你說你是處女座的,而且你還是個苦逼的后端程序員!

你是說你見不了后台代碼里,被SQL玷污的滿目瘡痍的開發代碼!

啊哈,SQLSHOP聽過么,把SQL全部放到外置文件里進行統一管理,所有的查詢都是按照綁定變量的方式進行。

從不拼SQL,從不把SQL寫到代碼里,復雜的業務寫成存儲過程或函數。

SQLSHOP讓你的代碼一塵不染。

SQLSHOP讓你擔心的注入問題,執行計划問題輕松解決。

SQLSHOP讓你在寫代碼的歲月里幸福的像花兒一樣。

那什么地方有SQLSHOP呢?

啊哈,剛好本仙身上帶了一包,暫給元帥嘗嘗鮮,涉及一些不太方便的代碼,請自行腦補。

public class SQL 
{
    private Dictionary<int,string> Sqls{get;  set;}
    private Dictionary<string,object> Parameters{get;  set;}
    
    public SQL(Dictionary<int,string> sqls)
    {
        if (sqls==null||sqls.Count==0)throw new NotSupportedException("sql can't empty");
        this.Sqls=sqls;
        Parameters=new Dictionary<string,object>();
    }
    
   public void AsyncExecute<T>(Action<Exception> error,Action<T> back)
   {
        //...查詢數據庫返回數據並映射到對象上
   }
   
   public void Add(string pname,object value)
   {
           Parameters.Add(pname,value);
   }
   
   
   public void Clear()
   {
           Parameters.Clear();
   }
}
SQL class
public class SQLPath:DynamicObject
{
     private StringBuilder builder=new StringBuilder();
     
     public override bool TryGetMember(GetMemberBinder binder, out object result)
     {
           var name = binder.Name;
           builder.Append('\\');
           builder.Append(name);
           result=this;
           return true;
     }
     
     private SQLPath(){}
     
     public static dynamic RootPath
     {
         get
        {return new SQLPath();}
     }
     
     public SQL ToSQL()
     {
         return SQLShop.ReadSQL(this);
     }
     
     public string Path
     {
        get{
         return builder.ToString();
        }
     }
}
SQLPath class
public static class SQLShop
{
    public static SQL ReadSQL(SQLPath sqlpath)
    {
       var path=sqlpath.Path;
       Dictionary<int,string> sqls=new Dictionary<int,string>();
       //...按照文件組織或xml文件或者其他方式來讀取這種查詢下的全部sql,並做緩存
       //...獲取全部SQL,並取出每個SQL的SQL參數的生成hash值存入到sqls的鍵種
       sqls.Add(-1581397123,"SELECT USER_NAME ,USER_ID FROM T_BASE_USERS T WHERE T.USER_NAME LIKE :user_name");
       sqls.Add(24307103,"SELECT USER_NAME ,USER_ID FROM T_BASE_USERS T WHERE T.USER_NAME LIKE :user_name and T.ADDRESS LIKE :address");
       return new SQL(sqls);
    }
    
}
SQLShop class
void Main()
{
    var root=SQLPath.RootPath.UserManager.UserPower.QueryUser;//用戶管理-》權限管理-》查詢用戶
    var sql=(root as SQLPath).ToSQL();
    
    sql.Add("user_name","%王");
    sql.AsyncExecute<User>(
    ex=>
    {
        //發生異常
        Console.WriteLine(ex);
    },
    User=>
    {
       //取到正確數據
    });
    sql.Clear();
    
    sql.Add("user_name","王__");
    sql.Add("address","%西安%");
    sql.AsyncExecute<User>(
    ex=>
    {
        //發生異常
        Console.WriteLine(ex);
    },
    User=>
    {
       //取到正確數據
    });
}
demo

 

(SQLSHOP的思想不是做一個ORM,而是做一個SQL的管理器,統一管理這些SQL,而不是凌亂的散落在各個class文件里面。)

 

你說我總算發現了,你對我們這些功能齊全的ORM有偏見!

啊哈,你說對了!

不過我的偏見是有理由的哈!

關系本來就是該數據庫來處理,RDBMS的第一個R就是指關系,這個關系是說數據之間的數據關系。

OO語言里面也有關系,不過是對象關系,雖然可以將數據關系按照某個原則轉換到對象上!

但是為了按照數據關系來組織數據對象總感覺不是那么美好!

NH已經不是那么火熱了!

LINQ TO SQL也已經在慢慢消失。

EF雖然活着,但只是活在很多小的項目,或者懶的開發人員那里。

要想一套很好的ORM,想想NOSQL吧!

只需要單表映射,不要再把復雜的關系組織到OO上了。

就算某天覺得關系型數據庫不給力了,想換NOSQL。

噢耶,程序里面全是單表操作,so easy!

 

珍愛生命,遠離復雜的ORM!

那怎么判斷一個ORM是否復雜呢?

1.全部使用對象的方式來操作數據庫。(按理說,所有的開發人員應該都是見不到物理表的,所見的只能是視圖,函數,或存儲過程)

2.由機器自動生成SQL並執行。(EF生成的SQL好么,你用一張C#的內存表關聯一張數據庫的一張表試試看,那長長的SQL,那淡淡的憂傷)

3.包含復雜的查詢語法,企圖用一套自己的語法來通吃所有數據庫。(你明白的,通吃有用?學習啥語法都不如學好SQL,數據庫就那幾種,SQL都差不多的)

4.不承認我上邊說的的,還執迷不悔的,就當我啥都沒說,我沒有在說你哈!


免責聲明!

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



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