亚洲综合图片区自拍_思思91精品国产综合在线观看_一区二区三区欧美_欧美黑人又粗又大_亚洲人成精品久久久久桥本

ORM哪家強(qiáng)?java,c#,php,python,go 逐一對(duì)比, 網(wǎng)友直呼:全面客觀

2023-01-30 10:10:01 來源:51CTO博客

前言

最近一段時(shí)間,我使用??golang??開發(fā)了一個(gè)新的??ORM??庫(kù)。

為了讓這個(gè)庫(kù)更好用,我比較研究了各語言的主流??ORM??庫(kù),發(fā)現(xiàn)有一些語言的??ORM??庫(kù)確實(shí)很好用,而有另外一些語言的庫(kù)那不是一般的難用。


【資料圖】

然后我總結(jié)了他們呢的一些共性和差異點(diǎn),于是形成了本文的主要內(nèi)容。

本文會(huì)先說明什么是SQL編寫難題,以及探討一下 ??code first?? 和 ??database first?? 的優(yōu)缺點(diǎn)。然后依據(jù)這兩個(gè)問題的結(jié)論去審視目前主流后端語言??java??, ??c#??, ??php??, ??python??, ??go??各自的orm庫(kù),對(duì)比研究下他們的優(yōu)缺點(diǎn)。最后給出總結(jié)和參考文檔。

如果你需要做技術(shù)選型,或者做技術(shù)研究,或者類似于我做框架開發(fā),或者單純地了解各語言的差異,或者就是想吹個(gè)牛,建議保存或收藏。如果本文所涉及到的內(nèi)容有任何不正確,歡迎批評(píng)指正。

溫馨提示,本文會(huì)有一些戲謔或者調(diào)侃成分,并非對(duì)某些語言或者語言的使用者有任何歧視意見。如果對(duì)你造成了某些傷害,請(qǐng)多包涵。

什么是SQL編寫難題

如果你是做web開發(fā),那么必然需要保存數(shù)據(jù)到數(shù)據(jù)庫(kù),這個(gè)時(shí)候你必須熟悉使用sql語句來讀寫數(shù)據(jù)庫(kù)。

sql本身不難,命令也就那幾個(gè),關(guān)鍵字也不算多,但是為什么編寫sql會(huì)成為難題呢?

比如下面的sql

select * from user        insert user (name,mobile) values ("tang","18600000000")

它有什么難題? 簡(jiǎn)單的單表操作嘛,一點(diǎn)難題沒有,但凡學(xué)過點(diǎn)??sql??的程序員都能寫出來,并且保證正確。我估計(jì)比例能超過90%

但是,如果你需要寫下面的sql呢?

SELECT         article.*,        person.name as person_name     FROM article     LEFT JOIN person ON person.id=article.person_id     WHERE article.type = 0     AND article.age IN (18,20)

這個(gè)也不復(fù)雜,就是你在做查詢列表的時(shí)候,會(huì)經(jīng)常用到的聯(lián)表查詢。你是否還有勇氣說,寫出來的??sql??絕對(duì)正確。我估計(jì)比例不超過70%

再稍微復(fù)雜點(diǎn),如果是下面的sql?

SELECT         o.*,        d.department_name,        (SELECT Sum(so.goods_fee) AS task_detail_target_completed_tem          FROM sale_order so          WHERE so.merchant_id = "356469725829664768"          AND so.create_date BETWEEN (20230127) AND (20230212)          AND so.delete_state = 2          AND so.department_id = o.department_id        ) AS task_detail_target_completed     FROM task_detail o     LEFT JOIN department d ON d.department_id=o.department_id     WHERE o.merchant_id = "356469725829664768"     AND o.task_id = "356469725972271104768"

這是我項(xiàng)目里真實(shí)的sql語句,目的是統(tǒng)計(jì)出所有部門在某時(shí)間段內(nèi)各自的業(yè)績(jī)。邏輯上也不太復(fù)雜,但你是否還有勇氣說,寫出來的??sql??絕對(duì)正確。我估計(jì)比例不超過40%

如上面的sql所示,SQL編寫難題在于以下幾方面。

要保證字段正確

應(yīng)該有的字段不能少,不應(yīng)該有的字段不能多。

比如你把??mobile??誤打成??mobike??,這屬于拼寫錯(cuò)誤,但是這個(gè)拼寫錯(cuò)誤只有在實(shí)際運(yùn)行的時(shí)候才會(huì)告訴你字段名錯(cuò)了。

并且項(xiàng)目越大,表越多,字段越多,這種拼寫錯(cuò)誤發(fā)生的可能性越大。以至于可以肯定的說,100%的可能性會(huì)出現(xiàn)。

要特別注意sql語法

例如你在查詢的時(shí)候必須寫??from??,絕對(duì)不能誤寫成??form??,但是在實(shí)際開發(fā)過程中,很容易就打錯(cuò)了。

這種錯(cuò)誤,也只有運(yùn)行的時(shí)候才會(huì)告訴你語法錯(cuò)了。并且??sql??越復(fù)雜,這種語法錯(cuò)誤發(fā)生的可能性越大。

編輯器不會(huì)有sql的語法提示

常見的編碼用的軟件,對(duì)于sql相關(guān)的代碼,不會(huì)有語法提示,也不會(huì)有表名提示,字段名提示。

最終的代碼質(zhì)量如何全憑你的眼力,經(jīng)驗(yàn),能力。

很顯然,既然存在該難題,那么哪個(gè)ORM能解決該難題,就應(yīng)該算得上好,如果不能解決,則不能稱之為好。

什么是code first 和 database first

這倆概念并不是新概念,但是我估計(jì)大多數(shù)開發(fā)者并不熟悉。

所謂 code first, 相近的詞是 model fist, 意思是模型優(yōu)先,指的是在設(shè)計(jì)和開發(fā)系統(tǒng)時(shí),優(yōu)先和重點(diǎn)做的工作是設(shè)計(jì)業(yè)務(wù)模型,然后根據(jù)業(yè)務(wù)模型去創(chuàng)建數(shù)據(jù)庫(kù)。

所謂 database first,意思是數(shù)據(jù)庫(kù)優(yōu)先,指的是在設(shè)計(jì)和開發(fā)系統(tǒng)時(shí),優(yōu)先和重點(diǎn)做的工作是創(chuàng)建數(shù)據(jù)庫(kù)結(jié)構(gòu),然后去實(shí)現(xiàn)業(yè)務(wù)。

這里我提到了幾個(gè)詞語,可能在不同的語言里叫法不一樣,可能不同的人的叫法也不一樣,為了下述方便,我們舉例子來說。

code first 例子

假設(shè)我是一個(gè)對(duì)電商系統(tǒng)完全不懂的小白,手頭上也沒有如何設(shè)計(jì)電商系統(tǒng)的資料,我和我的伙伴只是模糊地知道電商系統(tǒng)主要業(yè)務(wù)就是處理訂單。

然后我大概會(huì)知道這個(gè)訂單,主要的信息包括哪個(gè)用戶下單,什么時(shí)間下單,有哪幾種商品,數(shù)量分別是多少,根據(jù)這些已有的信息,我可以設(shè)計(jì)出來業(yè)務(wù)模型如下

public class OrderModel {    //訂單編號(hào)    Integer orderId;    //用戶編號(hào)    Integer userId;    //訂單時(shí)間    Integer createTime;    //訂單詳情(包含商品編號(hào),商品數(shù)量)    String  orderDetail;}

很簡(jiǎn)單,對(duì)吧,這個(gè)模型很匹配我目前對(duì)系統(tǒng)的認(rèn)知。接下來會(huì)做各種業(yè)務(wù)邏輯,最后要做的是將訂單模型的數(shù)據(jù)保存到數(shù)據(jù)庫(kù)。但是在保存數(shù)據(jù)到數(shù)據(jù)庫(kù)的時(shí)候,就有一些考慮了。

我可以將上面??OrderModel??業(yè)務(wù)模型建立一張對(duì)應(yīng)表,里面的4個(gè)屬性,對(duì)應(yīng)數(shù)據(jù)表里的4個(gè)字段,這完全可以。但是我是電商小白,不是數(shù)據(jù)庫(kù)小白啊,這樣存儲(chǔ)的話,肯定不利于統(tǒng)計(jì)訂單商品的。

所以我換一種策略,將??OrderModel??的信息進(jìn)行拆分,將前三個(gè)屬性 orderId, userId, createTime 放到一個(gè)新的類里。然后將 orderDetail 的信息進(jìn)行再次分解,放到另一個(gè)類里

public class OrderEntity {    Integer orderId;    Integer userId;    Integer createTime;}public class OrderDetailEntity {    Integer orderDetailId;    Integer orderId;    Integer goodsId;    Integer goodsCount;}

最后,在數(shù)據(jù)庫(kù)建立兩張表??order??,??order_detail??,表結(jié)構(gòu)分別對(duì)應(yīng)類??OrderEntity??,??OrderDetailEntity??的結(jié)構(gòu)。

至此,我們完成了從業(yè)務(wù)模型??OrderModel??到數(shù)據(jù)表??order??,??order_detail??的過程。

這就是 code first ,注意這個(gè)過程的關(guān)鍵點(diǎn),我優(yōu)先考慮的是模型和業(yè)務(wù)實(shí)現(xiàn),后面將業(yè)務(wù)模型數(shù)據(jù)進(jìn)行分解和保存是次要的,非優(yōu)先的。

database first 例子

假設(shè)我是一個(gè)對(duì)電商系統(tǒng)非常熟悉的老鳥,之前做過很多電商系統(tǒng),那么我在做新的電商系統(tǒng)的時(shí)候,就完全可以先設(shè)計(jì)數(shù)據(jù)庫(kù)。

??order??表放訂單主要數(shù)據(jù),里面有xxx幾個(gè)字段,分別有什么作用,有哪些狀態(tài)值

??order_detail??表放訂單詳情數(shù)據(jù),,里面有xxx幾個(gè)字段,分別有什么作用

這些都可以很清楚和明確。然后根據(jù)表信息,生成??OrderEntity??,以及??OrderDetailEntity??即可開始接下來的編碼工作。這種情況下??OrderModel??可能有,也可能沒有。

這就是 database first ,注意這個(gè)過程的關(guān)鍵點(diǎn),我優(yōu)先考慮的是數(shù)據(jù)庫(kù)結(jié)構(gòu)和數(shù)據(jù)表結(jié)構(gòu)。

兩種方式對(duì)比

code first 模式下, 系統(tǒng)設(shè)計(jì)者優(yōu)先考慮的是業(yè)務(wù)模型??OrderModel??, 它可以描述清楚一個(gè)完整業(yè)務(wù),包括它的所有業(yè)務(wù)細(xì)節(jié)(什么人的訂單,什么時(shí)候的訂單,訂單包含哪些商品,數(shù)量多少),有利于設(shè)計(jì)者對(duì)于系統(tǒng)的整體把控。

database first 模式下, 系統(tǒng)設(shè)計(jì)者優(yōu)先考慮的是數(shù)據(jù)表??order??,??order_detail??,他們中任何一張表都不能完整的描述清楚一個(gè)完整業(yè)務(wù),只能夠描述局部細(xì)節(jié),不利于設(shè)計(jì)者對(duì)于系統(tǒng)的整體把控。

在這里,調(diào)皮的同學(xué)會(huì)問,在 database first 模式下, 我把??order??,??order_detail??的信息一起看,不就知道完整的業(yè)務(wù)細(xì)節(jié)了嗎?

確實(shí)是這樣,但這里有一個(gè)前提,前提是你必須明確的知道??order??,??order_detail??是需要一起看的,而你知道他們需要一起看的前提是你了解電商系統(tǒng)。 如果你設(shè)計(jì)的不是電商系統(tǒng),而是電路系統(tǒng),你還了解嗎?還知道哪些表需要一起看嗎?

至此,我們可以有以下粗淺的判斷:

對(duì)于新項(xiàng)目,不熟悉的業(yè)務(wù),code first 模式更適合一些

對(duì)于老項(xiàng)目,熟悉的業(yè)務(wù),database first 模式更合適一些

如果兩種模式都可以的話,優(yōu)先使用 code first 模式,便于理解業(yè)務(wù),把控項(xiàng)目

如果哪個(gè)ORM支持 code first , 我們可以稍稍認(rèn)為它更好一些

Java體系的orm

Java語言是web開發(fā)領(lǐng)域處于領(lǐng)先地位,這一點(diǎn)無可置疑。它的優(yōu)點(diǎn)很明顯,但是缺點(diǎn)也不是沒有。

國(guó)內(nèi)應(yīng)用比較廣泛的orm是Mybatis,以及衍生品Mybatis-plus等

實(shí)際上Mybatis團(tuán)隊(duì)還出了另外一款產(chǎn)品,MyBatis Dynamic SQL,國(guó)內(nèi)我見用的不多,討論都較少。英文還可以的同學(xué),可以看下面的文檔。

另外還有 jOOQ, 實(shí)際上跟 MyBatis Dynamic SQL 非常類似,有興趣的可以去翻翻

下面,我們舉一些例子,來對(duì)比一下他們的基本操作

Java體系的Mybatis

單就orm這一塊,國(guó)內(nèi)用的最多的應(yīng)該是Mybatis,說到它的使用體驗(yàn)吧,那簡(jiǎn)直是一言難盡。

你需要先定義模型,然后編寫??xml??文件用來映射數(shù)據(jù),然后創(chuàng)建mapper文件,用來執(zhí)行??xml??里定于的sql。從這個(gè)流程可以看出,中間的??xml??文件起到核心作用,里面不光有數(shù)據(jù)類型轉(zhuǎn)換,還有最核心的??sql??語句。

典型的??xml??文件內(nèi)容如下

            insert into user (id,name,mobile)        values (#{id},#{name},#{mobile})                update user set        name = #{name},        mobile = #{mobile}        where id = #{id}                delete from user where id = #{id}        

你在編寫這個(gè)??xml??文件的時(shí)候,這個(gè)手寫sql沒有本質(zhì)區(qū)別,一定會(huì)遇到剛才說到的??SQL編寫難題??。

Java體系的Mybatis-plus

這里有必要提一下 Mybatis-plus,它是國(guó)內(nèi)的團(tuán)隊(duì)開發(fā)出來的工具,算是對(duì)Mybatis的擴(kuò)展吧,它減少了??xml??文件內(nèi)容的編寫,減少了一些開發(fā)的痛苦。比如,你可以使用如下的代碼來完成以上相同的工作

userService.insert(user);    userService.update(user);    userService.deleteById(user);    List userList = userService.selectList(queryWrapper);

完成這些工作,你不需要編寫任何??xml??文件,也不需要編寫??sql??語句,如之前所述,減少了一些開發(fā)的痛苦。

但是,請(qǐng)你注意我的用詞,是減少了一些。

對(duì)于連表操作,嵌套查詢等涉及到多表操作的事情,它就不行了,為啥不行,因?yàn)楦揪筒恢С职 S龅竭@種情況,你就老老實(shí)實(shí)的去寫??xml??吧,然后你還會(huì)遇到剛才說到的??SQL編寫難題??。

Java體系的Mybatis3 Dynamic Sql

值得一提的是Mybatis3 Dynamic Sql,翻譯一下就是動(dòng)態(tài)sql。還是剛才說的國(guó)內(nèi)我見用的不多,討論都較少,但是評(píng)價(jià)看上去挺好。

簡(jiǎn)單來說,可以根據(jù)不同條件拼接出sql語句。不同于上面的Mybatis,這些sql語句是程序運(yùn)行時(shí)生成的,而不是提前寫好的,或者定義好的。

它的使用流程是,先在數(shù)據(jù)庫(kù)里定義好數(shù)據(jù)表,然后創(chuàng)建模型文件,讓然后通過命令行工具,將每一個(gè)表生成如下的支持文件

public final class PersonDynamicSqlSupport {    public static final Person person = new Person();    public static final SqlColumn id = person.id;    public static final SqlColumn firstName = person.firstName;    public static final SqlColumn lastName = person.lastName;    public static final SqlColumn birthDate = person.birthDate;    public static final SqlColumn employed = person.employed;    public static final SqlColumn occupation = person.occupation;    public static final SqlColumn addressId = person.addressId;    public static final class Person extends SqlTable {        public final SqlColumn id = column("id", JDBCType.INTEGER);        public final SqlColumn firstName = column("first_name", JDBCType.VARCHAR);        public final SqlColumn lastName = column("last_name", JDBCType.VARCHAR, "examples.simple.LastNameTypeHandler");        public final SqlColumn birthDate = column("birth_date", JDBCType.DATE);        public final SqlColumn employed = column("employed", JDBCType.VARCHAR, "examples.simple.YesNoTypeHandler");        public final SqlColumn occupation = column("occupation", JDBCType.VARCHAR);        public final SqlColumn addressId = column("address_id", JDBCType.INTEGER);        public Person() {            super("Person");        }    }}

可以看出,這里的主要功能能是將表內(nèi)的字段,與java項(xiàng)目里的類里面的屬性,做了一一映射。

接下來你在開發(fā)的時(shí)候,就不用關(guān)心表名,以及字段名了,直接使用剛才生成的類,以及類下面的那些屬性。具體如下

SelectStatementProvider selectStatement = select(id.as("A_ID"), firstName, lastName, birthDate, employed,occupation, addressId)        .from(person)        .where(id, isEqualTo(1))        .or(occupation, isNull())        .build()        .render(RenderingStrategies.MYBATIS3);        List rows = mapper.selectMany(selectStatement);

如上面的代碼,好處有以下四點(diǎn)

你不再需要手寫sql也不用在意字段名了,因?yàn)槭褂玫亩际穷?,或者屬性,編寫代碼的時(shí)候編輯器會(huì)有提示,編譯的時(shí)候如果有錯(cuò)誤也會(huì)提示,實(shí)際運(yùn)行的時(shí)候就不會(huì)有問題了。聯(lián)表查詢,嵌套查詢啥的,也都支持完美避開了??SQL編寫難題??

當(dāng)然帶來了額外的事情,比如你要使用工具來生成??PersonDynamicSqlSupport??類,比如你要先建表。

先建表這事兒,很明顯就屬于 ??database first?? 模式。

C#體系的orm

C# 在工業(yè)領(lǐng)域,游戲領(lǐng)域用的多一些,在web領(lǐng)域少一些。

它也有自己的orm,名字叫 Entity Framework Core, 一直都是微軟公司在維護(hù)。

下面是一個(gè)典型的聯(lián)表查詢

var id = 1;    var query = database.Posts                .Join(database.Post_Metas,                    post => post.ID,                    meta => meta.Post_ID,                    (post, meta) => new { Post = post, Meta = meta }                )                .Where(postAndMeta => postAndMeta.Post.ID == id);

這句代碼的主要作用是,將數(shù)據(jù)庫(kù)里的Posts表,與Post_Metas表做內(nèi)聯(lián)操作,然后取出Post.ID等于1的數(shù)據(jù)

這里出現(xiàn)的Post,以及Meta都是提前定義好的模型,也就是類。 ??Post.ID?? 是 Post 的一個(gè)屬性,也是提前定義好的。

整個(gè)功能的優(yōu)點(diǎn)很多,你不再需要手寫sql,不需要關(guān)心字段名,不需要生成額外類,也不會(huì)有語法錯(cuò)誤,你只需要提前定義好模型,完全沒有??SQL編寫難題??,很明顯就屬于 ??code first?? 模式。

對(duì)比java的Mybatis以及Mybatis3 Dynamic Sql來說,你可以腦補(bǔ)一下下面的場(chǎng)景

PHP體系的orm

php體系內(nèi),框架也非常多,比如常見的??laravel??,??symfony??,這里我們就看這兩個(gè),比較有代表性

PHP體系的laravel

使用php語言開發(fā)web應(yīng)用的也很多,其中比較出名的是??laravel??框架,比較典型的操作數(shù)據(jù)庫(kù)的代碼如下

$user = DB::table("users")->where("name", "John")->first();

這里沒有使用模型(就算使用了也差不多),代碼里出現(xiàn)的 users 就是數(shù)據(jù)庫(kù)表的名字, name 是 users 表里的字段名,他們是被直接寫入代碼的

很明顯它會(huì)產(chǎn)生??SQL編寫難題??

并且,因?yàn)槭窍仍O(shè)計(jì)數(shù)據(jù)庫(kù),肯定也屬于 ??database first?? 模式

PHP體系的symfony

這個(gè)框架歷史也比較悠久了,它使用了 Doctrine 找個(gè)類庫(kù)作為orm

使用它之前,也需要先定義模型,然后生成支持文件,然后建表,但是在實(shí)際使用的時(shí)候,還是和laravel一樣,表名,字段名都需要硬編碼

$repository = $this->getDoctrine()->getRepository("AppBundle:Product"); // query for a single product by its primary key (usually "id")// 通過主鍵(通常是id)查詢一件產(chǎn)品$product = $repository->find($productId); // dynamic method names to find a single product based on a column value// 動(dòng)態(tài)方法名稱,基于字段的值來找到一件產(chǎn)品$product = $repository->findOneById($productId);$product = $repository->findOneByName("Keyboard");// query for multiple products matching the given name, ordered by price// 查詢多件產(chǎn)品,要匹配給定的名稱和價(jià)格$products = $repository->findBy(    array("name" => "Keyboard"),    array("price" => "ASC"));

很明顯它也會(huì)產(chǎn)生??SQL編寫難題??

另外,并不是先設(shè)計(jì)表,屬于 ??code first?? 模式

python體系的orm

在python領(lǐng)域,有一個(gè)非常著名的框架,叫django, 另外一個(gè)比較出名的叫flask, 前者追求大而全,后者追求小而精

python體系的django

django推薦的開發(fā)方法,也是先建模型,但是在查詢的時(shí)候,這建立的模型,基本上毫無用處

res=models.Author.objects.filter(name="jason").values("author_detail__phone","name")    print(res)    # 反向    res = models.AuthorDetail.objects.filter(author__name="jason")  # 拿作者姓名是jason的作者詳情    res = models.AuthorDetail.objects.filter(author__name="jason").values("phone","author__name")    print(res)    # 2.查詢書籍主鍵為1的出版社名稱和書的名稱    res = models.Book.objects.filter(pk=1).values("title","publish__name")    print(res)    # 反向    res = models.Publish.objects.filter(book__id=1).values("name","book__title")    print(res)

如上連表查詢的代碼,values("title","publish__name") 這里面寫的全都是字段名,硬編碼進(jìn)去,進(jìn)而產(chǎn)生sql語句,查詢出結(jié)果

很顯然,它也會(huì)產(chǎn)生??SQL編寫難題??

另外,并不是先設(shè)計(jì)表,屬于 ??code first?? 模式

python體系的flask

flask本身沒有orm,一般搭配 sqlalchemy 使用

使用 sqlalchemy 的時(shí)候,一般也是先建模型,然后查詢的時(shí)候,可以直接使用模型的屬性,而無須硬編碼

result = session.               query(User.username,func.count(Article.id)).join(Article,User.id==Article.uid).group_by(User.id).order_by(func.count(Article.id).desc()).all()

如上 ??Article.id?? 即是 Article 模型下的 id 屬性

很顯然,它不會(huì)產(chǎn)生??SQL編寫難題??

另外,并不是先設(shè)計(jì)表,屬于 ??code first?? 模式

go體系的orm

在go體系,orm比較多,屬于百花齊放的形態(tài),比如國(guó)內(nèi)用的多得gorm以及gorm gen,國(guó)外比較多的ent, 當(dāng)然還有我自己寫的 arom

go體系下的gorm

使用gorm,一般的流程是你先建立模型,然后使用類似如下的代碼進(jìn)行操作

type User struct {  Id  int  Age int}type Order struct {  UserId     int  FinishedAt *time.Time}query := db.Table("order").Select("MAX(order.finished_at) as latest").Joins("left join user user on order.user_id = user.id").Where("user.age > ?", 18).Group("order.user_id")db.Model(&Order{}).Joins("join (?) q on order.finished_at = q.latest", query).Scan(&results)

這是一個(gè)嵌套查詢,雖然定義了模型,但是查詢的時(shí)候并沒有使用模型的屬性,而是輸入硬編碼

很顯然,它會(huì)產(chǎn)生??SQL編寫難題??

另外,是先設(shè)計(jì)模型,屬于 ??code first?? 模式

go體系下的gorm gen

gorm gen 是 gorm 團(tuán)隊(duì)開發(fā)的另一款產(chǎn)品,和mybaits下的Mybatis3 Dynamic Sql比較像

它的流程是 先創(chuàng)建數(shù)據(jù)表,然后使用工具生成結(jié)構(gòu)體(類)和支持代碼, 然后再使用生成的結(jié)構(gòu)體

它生成的比較關(guān)鍵的代碼如下

func newUser(db *gorm.DB) user {  _user := user{}  _user.userDo.UseDB(db)  _user.userDo.UseModel(&model.User{})  tableName := _user.userDo.TableName()  _user.ALL = field.NewAsterisk(tableName)  _user.ID = field.NewInt64(tableName, "id")  _user.Name = field.NewString(tableName, "name")  _user.Age = field.NewInt64(tableName, "age")  _user.Balance = field.NewFloat64(tableName, "balance")  _user.UpdatedAt = field.NewTime(tableName, "updated_at")  _user.CreatedAt = field.NewTime(tableName, "created_at")  _user.DeletedAt = field.NewField(tableName, "deleted_at")  _user.Address = userHasManyAddress{    db: db.Session(&gorm.Session{}),    RelationField: field.NewRelation("Address", "model.Address"),  }  _user.fillFieldMap()  return _user}

注意看,其中大多數(shù)代碼的作用是啥?不意外,就是將結(jié)構(gòu)體的屬性與表字段做映射關(guān)系

_user.Name 對(duì)應(yīng) name_user.Age 對(duì)應(yīng) age

如此,跟mybaits下的Mybatis3 Dynamic Sql的思路非常一致

典型查詢代碼如下

u := query.Usererr := u.WithContext(ctx).    Select(u.Name, u.Age.Sum().As("total")).    Group(u.Name).    Having(u.Name.Eq("group")).    Scan(&users)// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "group"

這是一個(gè)分組查詢,定義了模型,也使用了模型的屬性。

但是呢,它需要使用工具生成額外的支持代碼,并且需要先定義數(shù)據(jù)表

很顯然,它不會(huì)產(chǎn)生??SQL編寫難題??

另外,它是先設(shè)計(jì)表,屬于 ??database first?? 模式

go體系下的ent

ent 是 facebook公司開發(fā)的Orm產(chǎn)品,與 gorm gen 有相通,也有不同

相同點(diǎn)在于,都是利用工具生成實(shí)體與數(shù)據(jù)表字段的映射關(guān)系

不同點(diǎn)在于gorm gen先有表和字段,然后生成實(shí)體

ent是沒有表和字段,你自己手動(dòng)配置,配置完了一起生成實(shí)體和建表

接下來,看一眼ent生成的映射關(guān)系

const (  // Label holds the string label denoting the user type in the database.  Label = "user"  // FieldID holds the string denoting the id field in the database.  FieldID = "id"  // FieldName holds the string denoting the name field in the database.  FieldName = "name"  // FieldAge holds the string denoting the age field in the database.  FieldAge = "age"  // FieldAddress holds the string denoting the address field in the database.  FieldAddress = "address"  // Table holds the table name of the user in the database.  Table = "users")

有了映射關(guān)系,使用起來就比較簡(jiǎn)單了

u, err := client.User.        Query().        Where(user.Name("realcp")).        Only(ctx)

注意,這里沒有硬編碼

它需要使用工具生成額外的支持代碼,并且需要先配置表結(jié)構(gòu)

很顯然,它不會(huì)產(chǎn)生??SQL編寫難題??

另外,它屬于先設(shè)計(jì)表,屬于 ??database first?? 模式

go體系下的aorm

aorm 是我自己開發(fā)的orm庫(kù),吸取了ef core 的一些優(yōu)點(diǎn),比較核心的步驟如下

和大多數(shù)orm一樣,需要先建立模型,比如

type Person struct {        Id         null.Int    `aorm:"primary;auto_increment" json:"id"`        Name       null.String `aorm:"size:100;not null;comment:名字" json:"name"`        Sex        null.Bool   `aorm:"index;comment:性別" json:"sex"`        Age        null.Int    `aorm:"index;comment:年齡" json:"age"`        Type       null.Int    `aorm:"index;comment:類型" json:"type"`        CreateTime null.Time   `aorm:"comment:創(chuàng)建時(shí)間" json:"createTime"`        Money      null.Float  `aorm:"comment:金額" json:"money"`        Test       null.Float  `aorm:"type:double;comment:測(cè)試" json:"test"`    }

然后實(shí)例化它,并且保存起來

//Instantiation the struct    var person = Person{}        //Store the struct object    aorm.Store(&person)

然后即可使用

var personItem Person    err := aorm.Db(db).Table(&person).WhereEq(&person.Id, 1).OrderBy(&person.Id, builder.Desc).GetOne(&personItem)    if err != nil {        fmt.Println(err.Error())    }

很顯然,它不會(huì)產(chǎn)生??SQL編寫難題??

另外,它屬于先設(shè)計(jì)模型,屬于 ??code first?? 模式

總結(jié)

本文,我們提出了兩個(gè)衡量orm功能的原則,并且對(duì)比了幾大主流后端語言的orm,匯總列表如下

框架

語言

SQL編寫難題

code first

額外創(chuàng)建文件

MyBatis 3

java

有難度

不是

需要

MyBatis-Plus

java

有難度

不是

不需要

MyBatis Dynamic SQL

java

沒有

不是

需要

jOOQ

java

沒有

不是

需要

ef core

c#

沒有

不需要

laravel

php

有難度

不是

不需要

symfony

php

有難度

不是

需要

django

python

有難度

不是

不需要

sqlalchemy

python

沒有

不需要

grom

go

有難度

不需要

grom gen

go

沒有

不是

需要

ent

go

沒有

不是

需要

aorm

go

沒有

不需要

單就從這張表來說,不考慮其他條件,在做orm技術(shù)選型時(shí),

如果你使用java語言,請(qǐng)選擇 MyBatis Dynamic SQL 或者 jOOQ,因?yàn)檫x擇他們不會(huì)有??SQL編寫難題??

如果你使用c#語言,請(qǐng)選擇 ef core, 這已經(jīng)是最棒的orm了,不會(huì)有??SQL編寫難題??,支持??code first??,并且不需要額外的工作

如果你使用php語言,請(qǐng)選擇 laravel 而不是 symfony, 反正都有??SQL編寫難題??,那就挑個(gè)容易使用的

如果你使用python語言,請(qǐng)選擇 sqlalchemy 庫(kù), 不會(huì)有??SQL編寫難題??,支持??code first??,并且不需要額外的工作

如果你使用go語言,請(qǐng)選擇 aorm 庫(kù), 不會(huì)有??SQL編寫難題??,支持??code first??,并且不需要額外的工作

好了,文章寫兩天了,終于寫完了。如果對(duì)你有幫助,記得點(diǎn)贊,收藏,轉(zhuǎn)發(fā)。

如果我有說的不合適,或者不對(duì)的地方,請(qǐng)?jiān)谙旅婧莺莸呐u(píng)我。

參考文檔

??MyBatis 3??MyBatis-PlusMyBatis Dynamic SQLjOOQ: The easiest way to write SQL in JavaEntity Framework Core 概述 - EF Core | Microsoft Learn數(shù)據(jù)庫(kù)和Doctrine ORM - Symfony開源 - Symfony中國(guó) (symfonychina.com)Django(ORM查詢、多表、跨表、子查詢、聯(lián)表查詢) - 知乎 (zhihu.com)Sqlalchemy join連表查詢_FightAlita的博客-CSDN博客_sqlalchemy 連表查詢Gorm + Gen自動(dòng)生成數(shù)據(jù)庫(kù)結(jié)構(gòu)體_Onemorelight95的博客-CSDN博客_gorm 自動(dòng)生成??tangpanqing/aorm: Operate Database So Easy For GoLang Developer (github.com)??

標(biāo)簽: 拼寫錯(cuò)誤 的可能性 語法錯(cuò)誤

上一篇:
下一篇: