mORMot 1.18 第07章 簡單的讀寫操作

来源:https://www.cnblogs.com/hieroly/p/18160207
-Advertisement-
Play Games

C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...


mORMot 1.18 第七章 簡單的讀寫操作

本章描述了典型的數據讀寫操作。首先,我們將註意力集中在數據上,而不是函數。

讀取操作返回一個TID,它是一個32位或64位整數(取決於你的記憶體模型),反映了表的信息。TID在表中的每一行都是唯一的。

ORM的新手可能會感到驚訝,但通常你不需要創建SQL查詢來過濾請求,而是將其留給ORM來處理。

為什麼呢?原因有很多。

ORM理解你的數據模型,並且可以提出合理請求。ORM可以強制實施安全要求,而這些要求你很難附加到自己的SQL請求中。ORM可以處理資料庫技術中的差異,這些差異你必須瞭解並且進行硬編碼。這些差異使得一個典型的SQL項目很難移植到新的資料庫中,但對於ORM項目來說卻很容易。考慮以下SQL語句:


Firstname := 'Tom'; // 或 TEdit.Text
Database.Query('SELECT * FROM sampledata WHERE name = ?',[Firstname]);

在mORMot中,它將被寫成


Firstname := StringToUTF8( 'Tom'); // 或 TEdit.Text
Rec := TSQLSampleRecord.Create( Database, 'Name=?' ,[firstname]);

StringToUTF8處理適當的代碼頁轉換,以正確處理可能在第一個示例中無法正確處理的名稱,例如帶有重音符號、撇號等的名稱。

mORMot會構建一個類似的SQL語句,但也可以添加安全條件、SQL JOIN條件等。

以下是一個完整的示常式序,展示了mORMot的實際應用。我們稍後會對其進行剖析。

program sample1;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Classes,
  SynCommons,
  mORMot;
type
  TSQLSampleRecord = class(TSQLRecord)
  private
    fQuestion: RawUTF8;
    fName: RawUTF8;
    fTime: TModTime;
  published
    property Time: TModTime read fTime write fTime;
    property Name: RawUTF8 read fName write fName;
    property Question: RawUTF8 read fQuestion write fQuestion;
  end;

var
  Database: TSQLRest;
  Model: TSQLModel;

  procedure ModelCreate;
  begin
    writeln('creating model');
    Model := TSQLModel.Create([TSQLSampleRecord]);
  end;


  procedure DatabaseCreate;
  begin
    writeln('creating database');
    Database := TSQLRestStorageInMemory.Create(TSQLSampleRecord, nil, 'test.db', False);
  end;

  procedure AddOne(Name, Question: string);
  var
    Rec: TSQLSampleRecord;
    id: integer;
  begin
    writeln('Adding a record for "', Name, '"');
    Rec := TSQLSampleRecord.Create;
    try
 // we use explicit StringToUTF8() for conversion below
 Rec.Name := StringToUTF8(Name);
 Rec.Question := StringToUTF8(Question);
 id := Database.Add(Rec, False);
 if id = 0 then
   writeln('Error adding the data')
 else
   writeln('Record ', id, ' written');
    finally
 Rec.Free;
    end;
  end;


  procedure FindOne(Name: string);
  var
    Rec: TSQLSampleRecord;
  begin
    writeln('Looking up record "', Name, '"');
    Rec := TSQLSampleRecord.Create(Database, 'Name=?', [StringToUTF8(Name)]);
    try
 if Rec.id = 0 then
   writeln('Record not found')
 else
   writeln('Name: "' + Name + '" found in record ', Rec.id, ' with question: "', UTF8ToString(Rec.Question), '"');
    finally
 Rec.Free;
    end;
  end;

  procedure Shutdown;
  begin
    Database.Free;
    Model.Free;
  end;


begin

  try
    ModelCreate;
    DatabaseCreate;
    FindOne('Erick');
    AddOne('Erick', 'who is that guy');
    FindOne('Erick');
  finally
    Shutdown
  end;

end.   

您的應用程式通過創建TSQLRecord的派生數據對象(如本例中的TSQLSampleRecord)來與資料庫進行交互。


TSQLSampleRecord = class(TSQLRecord)

  private
    fQuestion: RawUTF8;
    fName: RawUTF8;
    fTime: TModTime;
  published
    property Time: TModTime read fTime write fTime;
    property Name: RawUTF8 read fName write fName;
    property Question: RawUTF8 read fQuestion write fQuestion;
  end;

我們首先定義資料庫模型,即我們將在程式中使用的所有TSQLRecord派生類的列表。這裡只有一個記錄模型,但如果有多個,我們會用逗號將它們分開。

然後我們根據模型創建一個資料庫。資料庫是我們與實際資料庫的連接,我們將使用它來讀取、寫入、刪除和更新數據。

在這個簡單的例子中,我們使用的是全局變數。


var
  Database: TSQLRest;
  Model: TSQLModel;

procedure ModelCreate;
begin
  writeln(' creating Model ');
  Model := TSQLModel.Create([TSQLSampleRecord]);
end;

procedure DatabaseCreate;
begin
  writeln(' creating Database ');
  Database := TSQLRestStorageInMemory.Create(TSQLSampleRecord, Nil, test.db ', False);
end;

Db.Add() 方法用於向資料庫的指定表中添加記錄。它接受第二個參數,一個布爾值,用於確定記錄是否應保持更新模式(完成時需要解鎖)。通常,我們只是讀取數據,所以更新標誌應為 FalseAdd 方法返回 TID,對於所有成功的操作,該值都大於零。


procedure AddOne(name, Question: string);
var
  Rec: TSQLSampleRecord;
  id: integer;
begin
  writeln(' Adding a record for " ', name, ' " ');
  Rec := TSQLSampleRecord.Create;
  try
    // 我們在下麵的轉換中使用顯式的 StringToUTF8()
    Rec.name := StringToUTF8(name);
    Rec.Question := StringToUTF8(Question);
    id := Database.Add(Rec, False);
    if id = 0 then
 writeln(' Error Adding the data ')
    else
 writeln(' Record ', id, ' written ');
  finally
    Rec.Free;
  end;
end;

try/finally 部分確保我們無論成員填充和資料庫添加是否成功,都會釋放 TSQLSampleRecord 對象。

我們可以通過帶參數的查詢來查找記錄。


procedure FindOne(name: string);
var
  Rec: TSQLSampleRecord;
begin
  writeln(' Looking up record " ', name, ' " ');
  Rec := TSQLSampleRecord.Create(Database, 'Name = ? ', [StringToUTF8(name)]);
  try
    if Rec.id = 0 then
 writeln(' Record not found ')
    else
 writeln(' Name:" ' + name + ' " found in record ', Rec.id, 'with question:" ', UTF8ToString(Rec.question), ' " ');
  finally
    Rec.Free;
  end;
end;

Finally, you need to close the database and release the model.


procedure Shutdown;
begin
  Database.Free;
  Model.Free;
end;

7.1 批量添加操作

進行批量操作的主要原因有兩個:

  1. 你希望操作是原子的——即它們要麼完全發生,要麼完全不發生。
  2. 你想要加速大量的添加操作。在常見問題解答中反覆出現的一個主題是如何優化速度,這既是可能的,也是推薦的。批量操作可以大大加快多次添加的速度。
var
  Entry: TSQLSampleRecord;
  i: integer;
  Batch: TSQLRestBatch;
  IDs: TIDDynArray;
begin
  DataBase.BatchStart(TSQLORM);
  Entry := TSQLSampleRecord.Create;
  try
    for i := 1 to 25 do
    begin
 Entry.Name := FormatUTF8('Name % i ', [i]);
 DataBase.BatchAdd(Entry, True);
    end;
  finally
    Entry.Free;
  end;
  if (DataBase.BatchSend(IDs) <> HTML_SUCCESS) then
    writeln(' ERROR adding Batch ');
end;

如上所示,相同的Entry對象在每次添加時都被重覆使用,這樣你可以很容易地在迴圈外部設置常量,並且它們將保留其值。

7.2 讀取資料庫數據

從資料庫中讀取數據有幾種不同的方式:

  1. 依次讀取一條記錄。
  2. 使用類似'WHERE'的子句讀取一條記錄。
  3. 使用類似WHERE的子句(例如,Name like %,其中%是通配符)讀取一系列記錄。
  4. 讀取一系列記錄和相關記錄。

7.3 依次讀取記錄

通常,你可能想從第一條記錄開始迴圈遍曆數據庫,直到遍歷完所有記錄。使用Database.Retrieve函數,失敗時返回0。你可以將id設置為任何有效值。

var
  parent: TSQLParent;
  id: integer;
begin
  parent := TSQLparents.Create;
  id := 1;
  try
    while True do
    begin
 if Database.Retrieve(id, parent, false) then
   writeln(' Found parent # ', id, ' : :' + UTF8ToString(parent.pnt_name))
 else
   break;
 inc(id);
    end;
  finally
    parent.Free;
  end;
end;

7.4 使用類似WHERE的子句讀取一條記錄

mORMot不需要WHERE,但它確實允許你指定類似WHERE的子句。

var
  kid: TSQLKids;
begin
  kid := TSQLKids.Create(Database, 'kid_name LIKE ? ', [wildcard]);
  try
    if kid.id > 0 then
 writeln(' ID=', kid.id, ' Name= ', kid.kid_name);
  finally
    kid.Free;
  end;
end;

請註意,參數可以包含撇號或任何其他有效的UTF8字元。

7.5 使用類似WHERE的子句讀取一系列記錄

當然,有時你會連續讀取多條記錄,例如所有住在Peterborough的人,或者所有名字以S開頭的孩子(S-通配符)。你可以使用一次 CreateAndFillPrepare(),然後對每個記錄使用 FillOne()

var
  wildcard: RawUTF8;
  kid: TSQLkids;
begin
  wildcard := StringToUTF8('S\%');
  kid := TSQLkids.CreateAndFillPrepare(Database, 'kid_name LIKE ?', [wildcard]);
  if Assigned(kid) then
    try
 while kid.FillOne do
   writeln(' ID=', kid.id, ' Name= ', kid.kid_name);
    finally
 kid.Free;
    end;
end;

要有多個條件,請指定多個?和欄位。

kid := TSQLkids.CreateAndFillPrepare(Database,'kid_name LIKE ? AND kid_age < ? ', [wildcard, 4]);

7.6 更新記錄

通常你會讀取一條記錄,然後更新它。

var
  parent: TSQLparents;
  id: integer;
begin
  parent := TSQLparents.Create;
  id := 1;
  try
    if Database.Retrieve(id, parent, True) then
    begin
 parent.pnt_name := 'Smith';
 Database.Update(parent);
    End;
  finally
    parent.Free;
  end;
end;

7.7 添加或更新

Database.AddOrUpdate()的功能與Add()類似,但如果發現已存在的記錄,它會更新該記錄。

7.8 刪除記錄

一旦你使用上述記錄查找代碼定位到記錄的TID,你就可以刪除該記錄。

var
  id: integer;
begin
  id := 25;
  aServer.Delete(TParent, id);
end;

可以在批處理操作中刪除多條記錄,這當然會加快處理速度。

7.9 數據類型

mORMot將原生CPU和複合類型轉換為資料庫數據類型。每種資料庫的類型都略有不同,但此表格顯示了SQL3Lite轉換的示例。

Delphi SQLite3 備註
Byte INTEGER
Word INTEGER
Integer INTEGER
Cardinal N/A 應使用Int64代替
Int64 INTEGER
Boolean INTEGER 0為假,其他值均為真
enumeration INTEGER 存儲枚舉項的序數值(例如,第一個元素的序數值從0開始)
Set INTEGER 每一位對應一個枚舉項(一個欄位最多可以存儲64個元素)
Single FLOAT
Double FLOAT
Extended FLOAT 存儲為double類型(精度損失)
Currency FLOAT 可安全地與貨幣類型進行相互轉換,具有固定的小數位數,無舍入誤差
RawUTF8 TEXT 這是ORM中存儲一些文本內容的首選欄位類型
WinAnsiString TEXT Delphi中的WinAnsi字元集(代碼頁1252)
RawUnicode TEXT Delphi中的UCS2字元集,如AnsiString
WideString TEXT UCS2字元集,如COM BSTR類型(所有版本的Delphi中的Unicode)
SynUnicode TEXT 在Delphi 2009之前為WideString,之後為UnicodeString
String TEXT 不建議在Delphi 2009之前使用(除非您希望在轉換過程中丟失某些數據)-在所有情況下,首選RawUTF8
TDateTime TEXT ISO 8601編碼的日期時間
TTimeLog INTEGER 專有的快速Int64日期時間
TModTime INTEGER 當記錄被修改時,將存儲伺服器日期時間(作為專有的快速Int64)
TCreateTime INTEGER 當記錄被創建時,將存儲伺服器日期時間(作為專有的快速Int64)
TSQLRecord INTEGER 32位RowID指向另一條記錄(警告:欄位值包含pointer(RowID),而不是有效的對象實例-必須通過其ID使用PtrInt(Field)類型轉換或Field.ID方法,通過後期綁定來檢索記錄內容),或者使用例如CreateJoined() - 在Win64下為64位
TID INTEGER 64位RowID指向另一條記錄,但不包含有關對應表的任何信息
TSQLRecordMany 數據存儲在單獨的透視表中;這是TSQLRecord的一個特殊情況:它不包含pointer(RowID),而是一個實例
TRecordReference INTEGER 通過在類似於RecordRef的Int64值中存儲ID和TSQLRecord類類型,能夠連接模型中的任何表的任何行,自動重置為0
TPersistent TEXT JSON對象(ObjectToJSON)
TCollection TEXT JSON對象數組(ObjectToJSON)
TObjectList TEXT JSON對象數組(ObjectToJSON)-參見TJSONSerializer.RegisterClassForJSON
TStrings TEXT 字元串的JSON數組(ObjectToJSON)
TRawUTF8List TEXT 字元串的JSON數組(ObjectToJSON)
any TObject TEXT 參見TJSONSerializer.RegisterCustomSerializer
TSQLRawBlob BLOB 此類型是RawByteString的別名
dynamic arrays BLOB 採用TDynArray.SaveTo二進位格式
Variant TEXT JSON中的數字或文本,或用於JSON對象或數組的TDocVariant自定義變體類型
Record TEXT JSON字元串或對象,自Delphi XE5起直接處理,或在先前版本中通過重寫TSQLRecord.InternalRegisterCustomProperties在代碼中定義
TRecordVersion INTEGER 64位版本號,每次修改對象時都會單調更新,以允許遠程同步

7.10 Joining Data Tables 連接數據表 形成多對多的關係

Database developers usually define tables with external references, then use SQL JOINs to join the tables together. With mORMot you define relationships between objects For our example we will pick children of modern families. Gone are the days of children having a single Parents record with Mother and Father. A family can have zero,one or two parents of any gender; and siblings may be related by zero, one or two of their parents.

IMPORTANT: Mormot does not normally download sub-tables. Rather, it just loads the TID of the specified sub-table. Likewise, when you save a table, you save the TID of the sub-table. Like all good rules, there are exceptions. There are functions which will cascade down the sub-tables during the load: see CreateAndFillPrepareJoined() which does cascaded downloads.

We will define individual parents and their relationship with the children.

資料庫開發者通常會定義帶有外部引用的表,這時使用SQL的JOIN操作將這些表連接起來。在使用mORMot時,你需要定義對象之間的關係。以現代家庭的孩子為例,過去那種孩子只有一條包含父母雙方信息的記錄的時代已經過去了。在mORMot體系中一個家庭的“父母”可以是 0 個,1個,2個或者任意多個;兄弟姐妹之間可能通過0個、1個或2個父母形成聯繫。

重要提示:mORMot通常不會下載子表。相反,它只會載入指定子表的TID(表標識符)。同樣,當你保存一個表時,你保存的是子表的TID。和所有好的規則一樣,也有例外。有一些函數可以在載入時級聯下載子表:參見執行級聯下載的CreateAndFillPrepareJoined()函數。

我們將定義父母與孩子之間的主從(或父子)數據關係。

(註:TID,即表標識符,是資料庫中對錶的唯一標識。在mORMot框架中,通常使用TID來引用和操作數據表。)

接下來,我們將繼續翻譯上述Pascal代碼:

type

  // 定義性別類型

  Tgender = (gMALE, gFEMALE);

  // 父母類

  TSQLparents = class(TSQLRecord)
  private
    fname: RawUTF8; // 名字
    fgender: Tgender; // 性別
  published
    property pnt_name: RawUTF8 read fname write fname; // 名字屬性
    property pnt_gender: Tgender read fgender write fgender; // 性別屬性
  end;

  // 孩子類

  TSQLkids = class(TSQLRecord)
  private
    fname: RawUTF8; // 名字
    fbirthdate: TDateTime; // 出生日期
    fparent1: TSQLparents; // 父親或母親1
    fparent2: TSQLparents; // 父親或母親2
  published
    property kid_name: RawUTF8 read fname write fname; // 孩子名字屬性
    property kid_birthdate: TDateTime read fbirthdate write fbirthdate; // 孩子出生日期屬性
    property kid_parent1: TSQLparents read fparent1 write fparent1; // 孩子父親或母親1屬性
    property kid_parent2: TSQLparents read fparent2 write fparent2; // 孩子父親或母親2屬性
  end;

首先,我們定義並創建了模型和資料庫,然後就可以開始了。

var
  Model: TSQLModel; // SQL模型
  Database: TSQLRest; // 資料庫
Const
  DBFILE = 'Database.db3'; // 資料庫文件

// 創建示例模型的函數
function CreateSampleModels: TSQLModel;
begin
  result := TSQLModel.Create([TSQLkids, TSQLparents]); // 創建一個包含孩子和父母類的模型
end;

var
  parent1, parent2, parent3: TID; // 父母ID
begin
  try
    Model := CreateSampleModels; // 創建模型
    Database := TSQLRestServerDB.Create(Model, DBFILE); // 創建資料庫
    TSQLRestServerDB(Database).CreateMissingTables; // 創建缺失的表

    // 現在我們可以添加父母信息了
    parent1 := AddParentData(Database, ' Jenny '); // 添加Jenny
    parent2 := AddParentData(Database, ' Hermann '); // 添加Hermann
    parent3 := AddParentData(Database, ' Karen '); // 添加Karen

    // 添加孩子信息
    AddKidData(Database, ' Tim ', parent1, parent2); // Tim的父母是Jenny和Hermann
    AddKidData(Database, ' Chris ', parent2, parent3); // Chris的父母是Hermann和Karen
    AddKidData(Database, ' George ', parent3, 0); // George的母親是Karen,沒有父親
  finally
    // ... 後續代碼
  end;
end.

我相信使用像AddParentData()、AddKidData()等工作函數會使程式更易於閱讀。在這個例子中,Jenny和Hermann是Tim的父母,Hermann和Karen是Chris的父母,而Karen是George的唯一母親。

// 向資料庫中添加父母數據的函數
function AddParentData(Database: TSQLRest; parentname: string): TID;
var
  parent: TSQLparents; // 父母對象
begin
  parent := TSQLparents.Create; // 創建父母對象
  try
    parent.pnt_name := parentname; // 設置父母名字
    result := Database.Add(parent, True); // 將父母對象添加到資料庫,並返回其ID
    if result = 0 then // 如果添加失敗(返回ID為0)
      writeln(' ERROR: 添加父母失敗:', parentname) // 輸出錯誤信息
    else
      writeln(' SUCCESS: 添加父母成功:', parentname); // 輸出成功信息
  finally
    parent.Free; // 釋放父母對象
  end;
end;
function AddKidData(Database: TSQLRest; kidname: string; parent1, parent2: TID): TID;

var
  kid: TSQLkids;
  parentA, parentB: TSQLParents;
begin
  kid := TSQLkids.Create;
  try
    kid.kid_name := StringToUTF8(kidname);

    parentA := TSQLParents.Create(Database, parent1);
    kid.kid_parent1 := TSQLParents(parentA);

    parentB := TSQLParents.Create(Database, parent2);
    kid.kid_parent2 := TSQLParents(parentB);

    result := Database.Add(kid, True);
    if result = 0 then
      writeln('錯誤:添加孩子失敗:', kidname)
    else
      writeln('成功:添加孩子:', kidname);
  finally
    kid.Free;
    parentA.Free;
    parentB.Free;
  end;
end;

如您所見,這是可讀性很高的代碼,很難出錯。

一旦添加了數據,就該讀取它們了。


procedure ShowChildrenManyJoined(Database: TSQLRest);

var
  kid: TSQLkids;
  wildcard: RawUTF8;
begin
  writeln('聯接表');
  writeln('================');

  wildcard := StringToUTF8('%');

  // kid.CreateJoined( Database, kid.kid_parent1);

  kid := TSQLkids.CreateAndFillPrepare(Database, 'SELECT k.* FROM kids k JOIN parents p1 ON k.kid_parent1=p1.id JOIN parents p2 ON k.kid_parent2=p2.id WHERE k.kid_name LIKE ?', [], [wildcard]);

  if Assigned(kid) then
    try
      while kid.FillOne do
        writeln('ID=', kid.ID, ' 姓名=', kid.kid_name, ' 父親=', kid.kid_parent1.pnt_name, ', 母親=', kid.kid_parent2.pnt_name);
      kid.FillClose;
    finally
      kid.Free;
    end;

end;

註意:與前面的翻譯相比,這裡的翻譯和修改更加精確,並且已經糾正了原始代碼中的錯誤(如將parent更正為parentB等)。同時,也根據中文語境調整了輸出文本。此外,在SQL查詢語句中,我增加了一個完整的聯接查詢示例,用於在ShowChildrenManyJoined過程中從資料庫中檢索孩子的信息以及他們的父母信息。這樣的查詢可以更高效地獲取相關數據,而不是對每個孩子單獨執行查詢。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近在翻《c++函數式編程》的時候看到有一小節在說c++14新增了“菱形運算符”。我尋思c++里好像沒什麼運算符叫這名字啊,而且c++14新增的功能很少,我也不記得有添加這種語法特性。一瞬間我有些懷疑我的記憶了,所以為了查漏補缺,我寫了這篇文章。 什麼是菱形運算符 這個概念在Java里比較多見: L ...
  • 前言 在實際開發過程中,如果後端需要啟用https訪問,通常項目啟動後配置nginx代理再配置https,前端調用時高版本的chrome還會因為證書未信任導致調用失敗,通過摸索整理一套開發調試下的https方案,特此分享 後端配置 生成HTTPS密鑰 keytool -genkeypair -ali ...
  • 前言 只有自己封裝庫的時候,才知道造輪子有多累。之前使用Python的時候,基本都只需要import,隨便哪個功能都有人寫好輪子用。不過造輪子也有好處,可以瞭解一些比較基礎的知識。 其實aardio也有很多已經造好的輪子可以用,只是因為只有作者在維護,而且沒有一個活躍的社區,所以很多方面有些缺失,比 ...
  • 一般來說Maven都是配合著idea一起使用,下載依賴速度慢就去網上找個鏡像配置一下,但總會遇到莫名其妙的問題,比如鏡像源不生效、Error reading file pom.xml等等。今天詳細講解一下maven配置文件settings.xml的配置方法。 小知識 maven的配置文件存在於兩個地 ...
  • 1. JUnit 最佳實踐指南 原文: https://howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/ 我假設您瞭解 JUnit 的基礎知識。 如果您沒有基礎知識,請首先閱讀(已針 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...