EF 中 Code First 的數據遷移以及創建視圖


寫在前面:

EF 中 Code First 的數據遷移網上有很多資料,我這份並沒什么特別。Code First 創建視圖網上也有很多資料,但好像很麻煩,而且親測好像是無效的方法(可能是我太笨,沒搞成功),我摸索出了一種簡單有效的方法,這里分享給大家。

 

 

EF是Entity Framework(實體框架)的簡寫,是微軟出品的用來操作數據庫的一個框架,會ASP.NET MVC的朋友對他肯定都不陌生。由於學藝不精,我對EF存在一疑慮,就不以【提問】的方式來問了,我以【總結】的方式來表達,如果總結有誤的地方,還請看到的大神可以指正,並賜教我正確的認知,萬分感謝。

EF有三種使用方式:

1) Db First 數據庫優先

2) Model First 模型優先

3) Code First 代碼優先

上圖中,前三種分別是DbFirst、ModelFirst和CodeFirst,而第4種也是CodeFirst。

 

一、DbFirst、ModelFirst必須從app.config/web.config中讀取連接字符串,簡直無情

 不知道是我功底太差,還是微軟真的就是這么設計的,我發現一個問題:DbFirst和ModelFirst這兩種模式,居然只能從App.config/Web.config中讀取數據庫連接字符串這是一個致命的問題,這意味着連接字符串不能被加密必須暴露給客戶看(如果你是窗體應用程序的話)。(感謝 @lcs-帥 指正這一點) 這意味着我們必須要 這樣(利用ASP.NET加密和解密Web.config中連接字符串) 來對我們的連接字符串進行加密,好像有點太復雜了。

如果不利用上面紅色大字中提到的方法,那我們大概可以有兩種方式讀取數據庫連接字符串,第一種是在App.config/Web.config中讀取:

1 <connectionStrings>
2     <add name="Model1" connectionString="data source=(LocalDb)\v11.0;initial catalog=數據庫名;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="..略.." />
3 </connectionStrings>

這種方式不太好,因為如果是窗體應用程序的話,等於就用明文告訴了別人你的數據庫密碼了。當然,你也可以對這一段字符串進行加密,就像這樣:

1 <connectionStrings>
2      <add name="Model1" connectionString="ZGF0YSUyMHNvdXJjZSUzRCUyOExvY2FsRGIlMjklNUN2MTEuMCUzQmluaXRpYWwlMjBjYXRhbG9nJTNEJXU2NTcwJXU2MzZFJXU1RTkzJXU1NDBEJTNCaW50ZWdyYXRlZCUyMHNlY3VyaXR5JTNEVHJ1ZSUzQk11bHRpcGxlQWN0aXZlUmVzdWx0U2V0cyUzRFRydWUlM0JBcHAlM0RFbnRpdHlGcmFtZXdvcms=" providerName="..略.." />
3 </connectionStrings>

而當你像上面這樣對數據庫連接字符串進行加密,此時你就等同於選擇了使用第二種方式讀取連接字符串了,第二種讀讀取數據庫連接字符串的方式是:

1 string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["Model1"].ConnectionString; //可選
2 connStr = 解密(connStr); //可選
3 Model1 db = new Model1(connStr); //第二種設置數據庫連接字符串的方式

這第二種方式的前2句代碼是可選的,也就是說你不一定要從Web.config/App.config中讀取數據庫連接字符串,你也不一定要對數據庫連接字符串進行加解密。

這第二種方式最重要的是第3句代碼,也就是說你可以使用一個字符串變量來做為數據庫連接字符串,這意味着你不一定要從Web.config/App.config中讀取數據庫連接字符串。

然而!可惜的是:在DbFirst和ModelFirst中,並不支持第二種設置數據庫連接字符串的方式,這也就意味着DbFirst和ModelFirst的應用場景大打折扣!

在DbFirst或ModelFirst中,調用以下代碼會報錯,因為只有一個無參構造方法:

 

也許你(曾經我)自做聰明的想到一些辦法,寫一個【部分類】為 DbContext 添加一個有參構造函數:

事實證明是自做聰明,當你去操作任何一張表的時候,就報這個錯誤:

當你(我)看到這一個錯誤提示的時候,終於認命了:在DbFirst和ModelFirst中,數據庫連按字符串只能寫在App.config/Web.config中,簡直無情。

 

 

二、CodeFirst 可以從代碼中讀取數據庫連接字符串,不必從Web.config/App.config中讀取。

 要在CodeFirst中對連接字符串進行加密,首先要添加一個帶參構造函數,就像這樣:

1 public Model1()
2     : base("name=Model11")
3 {
4 }
5 public Model1(string nameOrConnectionString)
6     : base(nameOrConnectionString)
7 {
8 }

然后就這樣:

1 string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["Model1"].ConnectionString; //可選
2 connStr = 解密(connStr); //可選
3 Model1 db = new Model1(connStr); //第二種設置數據庫連接字符串的方式

從配置文件中讀取出加了密的連接字符串,再進行解密,最后應用於 DbContext 之中。

在CodeFirst中進行這樣的操作程序不會報錯,簡直有愛。

 

三、【空 Code First 模型】與【來自數據庫的 Code First 】殊途同歸,是一樣的

關於Code First,有兩個可以選擇,下圖中的最后兩個:

這兩者是殊途同歸,是一樣的。

【空CodeFirst模型】就是新建一個空的模型,然后自己寫實體類代碼,根據這些實體類代碼來生成數據庫,生成數據庫了之后,就與【來自數據庫的CodeFirst】是一樣的。

【來自數據庫的CodeFirst】就是根據從數據庫中選擇的一些表/視圖來生成實體類代碼,這些自動生成的代碼和你自己手寫是一樣一樣的,也就是與【空CodeFirst模型+手寫實體類代碼】是一樣的。

然而,並不完全是!慢慢聊吧。

 

四、數據遷移

數據遷移,就是實體模型類發生變化之后(比如多一個字段,字段類型改變,或者多了一個實體類),數據庫的表結構也跟着一起變化的過程。

 

4.1 為什么要使用數據遷移

因為模型實際的數據庫結構可能會不一樣,不一樣的話程序運行就會有問題,所以需要使用數據遷移這個功能來幫助我們解決問題。

用一個例子來說明,創建控制台應用程序,創建【空CodeFirst模型】:

 1 //數據庫Model1
 2 public class Model1 : DbContext
 3 {
 4     public Model1() : base("name=Model1") { }
 5     public virtual DbSet<MyEntity> MyEntities { get; set; }
 6 }
 7 //實體類 (對應表:MyEntities)
 8 public class MyEntity
 9 {
10     public int Id { get; set; }
11     public string Name { get; set; }
12 }

修改數據庫連接字符串,改成一個我們熟悉的數據庫服務器名,以免數據庫新建了之后,找不到在哪里:

<add name="Model1" connectionString="server=服務器名;uid=用戶名;pwd=密碼;database=新的數據庫名;" providerName="System.Data.SqlClient" />

然后在Main方法中隨便訪問一下這個實體類:

1 using (var db = new Model1())
2 {
3     //隨便訪問一下 MyEntities 表,以便讓 EF 自動創建此表
4     var x = db.MyEntities.Find(1);
5 }

運行程序,就會得到一個新的數據庫,新數據庫里面有一個新表 MyEntities。(還有另一個叫 __MigrationHistory 的表,是用於記錄代碼遷移的歷史記錄,也是代碼遷移模式的開關,后面慢慢聊)

  

到這里為止,一切都正常

現在,我們再添加一個年齡Age字段:

1 //實體類 (對應表:MyEntities)
2 public class MyEntity
3 {
4     public int Id { get; set; }
5     public string Name { get; set; }
6     //添加了年齡字段
7     public int? Age { get; set; }
8 }

這時,再運行程序,就會報一個錯誤:

錯誤的大概意思就是:模型實際數據庫結構不一致,需要使用 Code First 中的數據遷移功能來解決問題。

 

4.2 數據遷移的用法

當模型與實際數據庫結構不一致時,就需要使用數據遷移。數據遷移我們只需要掌握三個方法就可以了,它們分別是:

1) 在當前項目中啟用數據遷移  Enable-Migrations

2) 添加遷移版本 Add-Migration 版本名稱

3) 更新數據庫 Update-Database

首先第一步,需要在當前項目中啟用數據遷移,打開【視圖->其它窗口->程序包管理器控制台】快捷鍵是 Alt+V,E,O,然后輸入命令:

Enable-Migrations

這樣就可以在當前項目中啟用數據遷移了,其效果是項目中會多出 Migrations 文件夾以及一些代碼:

Migrations 這個文件夾就是數據遷移的相關文件夾,做為初學者,不要亂動里面的代碼。

 

由於我們的模型已經發生了改變,所以需要添加一個新的遷移版本,在程序包管理控制台執行如下命令:

Add-Migration v1

其中的v1表示版本號,自己隨便取一個名字就可以了。此時,項目中多出一個文件:

這個文件的代碼是:

 1 //版本 v1
 2 public partial class v1 : DbMigration
 3 {
 4     //版本升級
 5     public override void Up()
 6     {
 7         //向 MyEntities 表添加 Age 字段
 8         AddColumn("dbo.MyEntities", "Age", c => c.Int());
 9     }
10         
11     //版本降級
12     public override void Down()
13     {
14         //向 MyEntities 表刪除 Age 字段
15         DropColumn("dbo.MyEntities", "Age");
16     }
17 }

代碼中的注釋是我寫上去的,大概的為大家解釋了一下是什么意思。到這里為止,數據庫依然沒有發生變化。

 

想要數據庫發生變化,多出一個 Age 字段,那就要用到第三個命令:

Update-Database

執行成功之后,數據庫就多出一個 Age 字段了。

此時,再運行程序,程序就不會報錯了。因為此時的模型實際數據庫結構已經一致。

至此,例子已演示完畢。

 

這里有一個非常非常非常重要的細節,要注意:

如果你使用了 new Model1(connStr) 自定義數據庫連接字符串,在使用數據遷移的命令時,所訪問的數據庫是你 web.config/app.config 中配置的數據庫,並不是你自定義連接的那個數據庫。

這是一個巨坑,一定要注意:

使用了自定義數據庫連接字符串時,雖然 web.config/app.config 中的明文數據庫連接字符串並不一定要被發布,但在開發時也一定要在里面填寫上正確的數據庫連接信息。

 

五、關閉數據遷移

數據遷移的開啟關閉分兩個層面來說:

1) Visual Studio 項目是否開啟了數據遷移

2) SQL Server 數據庫是否開啟了數據遷移

對於項目中是否開啟了數據遷移,識別方法是:有沒有 Migrations 這個文件夾以及里面的類文件。如果有就表示開啟了,沒有就沒開啟。

對於數據庫中是否開啟了數據遷移,識別方法是:有沒有 __MIgrationHistory 這個表。如果有就表示開啟了,沒有就沒開啟。

以下討論的數據遷移開啟和關閉,都是指數據庫中數據遷移的開啟和關閉。

 

實際上 Code First 又有兩種分支用法:

1) 數據庫中 啟用了數據遷移的 Code First 

2) 數據庫中 關閉了數據遷移的 Code First

這個開關並不在於你的項目中有沒有 Migrations 這個文件夾,而在於:你的數據庫里面,有沒有 __MigrationHistory 這個表

當你使用【空 Code First 模型】創建出來的數據庫,默認就是開啟了數據遷移的,關閉它的方法自然就是刪除 __MigrationHistory 這個表。

而你使用【來自數據庫的 Code First】默認這個數據庫就是關閉了數據遷移的 ,用一個例子來說明一下吧。

 

示例:

先確保你的數據庫實例中有一個數據庫,這個庫里面有一些表,比如 Student 表,並且這個庫沒有 __MigrationHistory 這個表。

然后新建控制台程序,並創建【來自數據庫的 Code First】,選擇 student 表,自動產生模型代碼和上下文類的代碼:

1 //這是自動產生的代碼 (我進行了刪減)
2 public partial class Model1 : DbContext
3 {
4     public Model1(): base("name=Model1") { }
5     public virtual DbSet<student> student { get; set; }
6 }
1 //這是自動產生的代碼 (我進行了刪減)
2 public partial class student
3 {
4     public int id { get; set; }
5     public string name { get; set; }
6 }

然后在 Main 方法里隨便調用一下,看看有沒有問題:

1 using (var db = new Model1())
2 {
3     //隨便調用一下,看看有沒有問題
4     var x = db.student.Find(1);
5 }

因為此時的模型實際數據庫結構是一樣的,運行結果當然不會有問題了。

 

現在,我們修改一下模型,在學生實體類中添加一個身份證的字段:

1 public partial class student
2 {
3     public int id { get; set; }
4     public string name { get; set; }
5     //添加身份證 idcard 字段
6     public string idcard { get; set; }
7 }

此時,我們再運行程序,程序報錯了,但報的錯誤並不是讓我們進行數據遷移:

報的錯誤是:列名 'idcard' 無效。

這就是數據庫中關閉了數據遷移的 Code First 的行為表現,不會提示你(要求你)進行數據遷移。

沒有了數據遷移,我們怎樣才能讓模型實際數據庫表結構一樣呢?

很簡單,你自己手動在數據庫 student 表中添加一個 idcard 字段不就可以了嗎。

確實,當我們手動添加了 idcard 字段之后,再運行程序,程序就不報錯了。

小總結:

1) 使用【空 Code First 模型】創建出來的數據庫默認是開啟數據遷移的,我們只需要刪除 __MigrationHistory 表就可以關閉數據遷移。

2) 使用【來自數據庫的 Code First】這種方式,數據庫默認就是關閉了數據遷移的。

3) 在數據庫中關閉數據遷移的優點是:

    你可能並不熟悉數據遷移是個什么鬼,那不如就讓它見鬼去吧。關閉它,會讓你進入你熟悉世界,通過手動改寫實體類,手動改數據庫表結構,來同步模型實際表結構,挺好!

 

六、在關閉數據遷移的模式下,在 EF 實體模型中創建視圖

數據庫關閉了數據遷移的情況下,要在 EF 實體模型中創建視圖,實在是太簡單了。

你就編寫一個實體類來當成視圖,比如 v_student,你就把它當成是一張表一樣來編寫:

1 //我想寫一個視圖,先別急,先當它是一張表
2 public partial class v_student
3 {
4     public int id { get; set; }
5     public string name { get; set; }
6     //
7     public string first_name { get; set; }
8 }
1 public partial class Model1 : DbContext
2 {
3     public Model1(): base("name=Model1") { }
4     public virtual DbSet<student> student { get; set; }
5     //我想寫一個視圖,先別急,先當它是一張表
6     public virtual DbSet<v_student> v_student { get; set; }
7 }

然后,在 Main 方法中訪問這個視圖,看看有沒有問題:

1 using (var db = new Model1())
2 {
3     //訪問一下這個視圖,看看有沒有問題
4     var x = db.v_student.Find(1);
5 }

運行。當然會有問題啦,會報這個錯誤:

注意到了嗎,它只是說 v_student 無效,並沒有說讓我們做什么數據遷移。

好吧,難道我們要傻傻的去創建一個 v_student 表嗎? 難道不可以創建一個 v_student 視圖?

當然可以,我們來創建一個視圖吧,在數據庫中執行以下SQL語句:

1 create view v_student
2 as
3 select id,name,substring(name,1,1) first_name from student
4 go

然后,測試運行程序,程序不報錯了。任務完成。

 

七、在開啟據遷移的模式下,在 EF 實體模型中創建視圖

也許你比較欣賞在數據庫中開啟了數據遷移的這種模式,在數據庫中開啟了數據遷移的模式下,能不能創建視圖呢?如果可以,又如何創建視圖呢?

網絡上你可以搜索到很多 Code First 中創建視圖的方法,這些方法都是指數據庫中開啟了數據遷移的 Code First 下的方法,但好像都挺麻煩的,反正我照着做並沒有做出來。

然后我摸索了一下,找出一種簡單又實用的方法,這里分享給大家。沒錯,這一段落才是本文最有價值的部分。

 

依然用例子來說明:

上接第四節【數據遷移】的例子,我們來添加一個 V_MyEntity 的視圖,代碼如下:

1 //我想寫一個視圖,先別急,先當它是一張表
2 public class V_MyEntity
3 {
4     public int Id { get; set; }
5     public string Name { get; set; }
6     //
7     public string First_Name { get; set; }
8 }
1 public class Model1 : DbContext
2 {
3     public Model1() : base("name=Model1") { }
4     public virtual DbSet<MyEntity> MyEntities { get; set; }
5     //我想寫一個視圖,先別急,先當它是一張表
6     public virtual DbSet<V_MyEntity> V_MyEntity { get; set; }
7 }

然后在 Main 方法隨便訪問一下這個視圖,看看可不可以:

1 using (var db = new Model1())
2 {
3     //訪問一下 V_MyEntity 視圖,看看可不可以
4     var x = db.V_MyEntity.Find(1);
5 }

運行程序,自然是報錯了:

因為模型實際數據庫表結構不一致,所以報錯了,由於數據庫中開啟了數據遷移的,所以會提示你(要求你)進行數據遷移。

 

此時,如果按照正常的步驟來進行數據遷移,我們將得到 V_MyEntity 這個表,這當然不是我們想要的結果,我們是要 V_MyEntity 視圖啊。

那就需要在數據遷移的過程中,做一點手腳,具體如下。

在程序包管理器控制台中輸入以下命令,以創建一個新的遷移版本:

Add-Migration v2

其中的 v2 表示版本號,其實可以隨便亂寫也行,只是個版本名字而已。

剛剛的操作使我們多出一個文件,內容如下(其中的中文注釋是我寫的,不是生成的):

 1 //代碼遷移版本:v2
 2 public partial class v2 : DbMigration
 3 {
 4     //版本升級
 5     public override void Up()
 6     {
 7         //創建表
 8         CreateTable(
 9             "dbo.V_MyEntity",
10             c => new
11                 {
12                     Id = c.Int(nullable: false, identity: true),
13                     Name = c.String(),
14                     First_Name = c.String(),
15                 })
16             .PrimaryKey(t => t.Id);
17             
18     }
19     //版本降級
20     public override void Down()
21     {
22         //刪除表
23         DropTable("dbo.V_MyEntity");
24     }
25 }

我們當然不想要創建表啦,我們要創建視圖,那就把這個文件改一改,改成如下這個樣子(本文最最最重要的環節):

 1 //代碼遷移版本:v2
 2 public partial class v2 : DbMigration
 3 {
 4     //版本升級
 5     public override void Up()
 6     {
 7         //創建視圖(本文最最最重要的環節)
 8         Sql(@"create view V_MyEntity as select id,name,substring(name,1,1) first_name from MyEntities");
 9     }
10     //版本降級
11     public override void Down()
12     {
13         //刪除視圖
14         Sql("drop view V_MyEntity");
15     }
16 }

改好之后,再執行數據遷移的最后一個命令,更新數據庫:

Update-Database

這個時候,我們發現數據庫沒有多出一個 V_MyEntity 的,而是多出了一個 V_MyEntity 的視圖,目的達到。

最后我們再運行程序,程序也沒有再報錯了,目的妥妥的達到。

 

八、在【來自數據庫的 Code First】中開啟數據遷移

先要復習幾個問題:

1) 用【空 Code First 模型】創建的數據庫,默認就是開啟數據遷移的。

2) 用【來自數據庫的 Code First】這種方式,其數據庫默認是關閉數據遷移的。

3) 判斷一個數據庫有沒有啟用數據遷移,辦法是:檢查有沒有 __MigrationHistory 表。

 

也許雖然你比較欣賞數據庫中開啟了數據遷移的這種模式,但是無奈你已經有一個數據庫啦,數據庫里80多張表也已經創建好啦,那我們當然要用【來自數據庫的 Code First】,來幫助我們自動生成這80多個實體類啦。

可是,對於一個已經存在的數據庫,我們能開啟這個數據庫的數據遷移模式嗎?答案當然也是可以的,具體操作如下。

 

比如我們導入了一個Student表:

1 //我進行了刪減
2 public partial class Student 
3 {
4     public int Id { get; set; }
5     public string Name { get; set; }
6 }
1 //我進行了刪減
2 public partial class Model1 : DbContext
3 {
4     public Model1() : base("name=Model1") { }
5     public virtual DbSet<Student> Student { get; set; }
6 }

然后二話不說,直接在項目中開啟代碼遷移(請注意這只是在項目中開啟代碼遷移,並沒有在數據庫中開啟代碼遷移):

Enable-Migrations

然后再二話不說,創建一個遷移版本:

Add-Migration v1

添加了遷移版本之后,會自動產生一個版本文件,內容如下(中文注釋是我寫的,不是自動生成的,也是我刪減的):

 1 //數據遷移版本名稱:v1
 2 public partial class v1 : DbMigration
 3 {
 4     //版本升級
 5     public override void Up()
 6     {
 7         //建表
 8         CreateTable("dbo.Student",..略..);
 9     }
10     //版本降級
11     public override void Down()
12     {
13         //刪表
14         DropTable("dbo.Student");
15     }
16 }

然后再二話不說,執行更新數據庫的操作(這等於是一口氣把數據遷移的三個命令挨個打了個遍):

Update-Database

然后就報錯了:

錯誤提示數據庫已經有Student這個表了,這個問題怎么解決呢?很好解決,辦法就是找到之前那個版本文件,把版本升級Up()方法中的代碼全部注釋掉,如下:

 1 //數據遷移版本名稱:v1
 2 public partial class v1 : DbMigration
 3 {
 4     //版本升級
 5     public override void Up()
 6     {
 7          //建表
 8          //CreateTable("dbo.Student",..略..); //注釋掉這些代碼是重要環節
 9     }
10     //版本降級
11     public override void Down()
12     {
13         //刪表
14         //DropTable("dbo.Student"); //注釋掉這些代碼是重要環節
15     }
16 }

注釋掉之后,再執行 Update-Database ,這次就不報錯了。

此時,數據庫中多了一個 __MigrationHistory 表,這表示數據庫的數據遷移功能已開啟,目的已達到:

最后,為了將來考慮,最好將剛剛注釋的代碼又取消注釋,這完全不影響你之后的使用。

 

總結:

1) EF 中只有 Code First 模式支持 new Model1(這里寫連接字符串),也就是說可以對其進行加密,這使得 Code First 成為大部分情況下的最佳選擇。

2) Code First 中,當模型實際表結構不一致時,程序會報錯,我們有兩種方式來使他們一致,一是手動修改模型代碼和表結構,二是使用數據遷移功能。

    這兩種方式,不是你想選哪一種就選哪一種的,取決於一個關鍵因素:數據庫是否開啟了數據遷移

3) 數據遷移的開啟,分兩個層面,一是項目的數據遷移開啟,二是數據庫的數據遷移開啟,前者並不怎么重要,后者決定了你需要手動還是自動來使模型實際表結構一致。

    項目中如果包含Migrations文件夾並且里面有相關的類,說明項目已開啟了數據遷移。 

    數據庫中如果有 __MigrationHistory 表,說明數據庫已開啟了數據遷移。

4) 刪除數據庫中的 __MigrationHistory 表,也就關閉了數據庫中數據遷移功能,關閉數據遷移的目的是:

    你可能並不熟悉數據遷移是個什么鬼,那不如就讓它見鬼去吧。關閉它,會讓你進入你熟悉世界,通過手動改寫實體類,手動改數據庫表結構,來使模型實際表結構一致,挺好!

5) 我的建議是:不要關閉數據遷移,還是可以嘗試學習一下數據遷移模式的。在程序包管理器控制台下,使用以下三個命令就可以使用數據遷移模式了:

    *) 在項目中啟用數據遷移  Enable-Migrations

    *) 創建遷移版本 Add-Migration 版本名稱

    *) 更新數據庫 Update-Database

6) 在數據庫關閉數據遷移的情況下,創建視圖的方式與創建表一樣,寫好實體類 V_ABC 之后,再到數據庫里創建 V_ABC 的視圖就行了。

7) 在數據庫開啟數據遷移的情況下,創建視圖的方式是先寫好 V_ABC 實體類,再添加遷移版本,然后在遷移版本的代碼中注釋創建表 V_ABC 的代碼,改為創建視圖 V_ABC 的代碼,最后執行數據遷移中的更新數據庫命令即可。

8) 巨坑:當你在執行數據遷移的三個命令時,它們永遠是在 Web.config/App.config 中讀取連接字符串!別誤以為是 new Model1(這里的字符串) 啦。

 

在 Code First 中使用數據遷移,以及視圖創建,示例下載

 


免責聲明!

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



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