C# Guidとは?生成方法・使い方・重複しない仕組みまで初心者向けに徹底解説
はじめに
C#でアプリケーションを開発していると、次のような英数字を目にすることがあります。
550e8400-e29b-41d4-a716-446655440000
これは「Guid(グローバル一意識別子)」と呼ばれる値です。データベースの主キー、ユーザーID、注文ID、ファイル名、APIで扱うリソースの識別子など、さまざまな場面で利用されます。
C#では、次の1行だけで新しいGuidを生成できます。
C#Guid id = Guid.NewGuid();
Guidの大きな特徴は、複数のコンピューターやアプリケーションで別々に生成しても、同じ値になる可能性が極めて低いことです。
この記事では、C#のGuidとは何か、生成方法や変換方法、重複しにくい仕組み、実践的な使い方、データベースで利用するときの注意点まで、初心者向けにわかりやすく解説します。
1. C#のGuidとは?初心者向けにわかりやすく解説
1-1. Guidは「重複しにくい一意な識別子」
Guidは、データやオブジェクトを識別するために使われる値です。
たとえば、通販サイトに次の3件の注文があるとします。
注文A:4a520636-1fd1-4e81-802d-29e763bd5dc1
注文B:c0436490-b35a-489d-ac67-27672553ad81
注文C:b1243479-2439-47fd-af4c-17ed78666765
それぞれの注文に異なるGuidを割り当てれば、注文番号が重複する可能性を極めて低くできます。
通常の連番IDでは、IDを発行するデータベースやサーバーに問い合わせて「次の番号」を取得します。一方、Guidは各コンピューターやアプリケーション内で生成できます。
複数のシステムが同時にIDを発行する場合でも衝突しにくいため、Web APIや分散システムとの相性がよい識別子です。
1-2. Guidの正式名称と基本的な意味
Guidは「Globally Unique Identifier」の略で、日本語では「グローバル一意識別子」などと訳されます。
単語を分けると、次のような意味になります。
Globally:世界的に、広い範囲で
Unique:一意の、重複しない
Identifier:識別子
つまりGuidは、「世界的な規模でも重複しにくい識別子」を表す言葉です。
ただし、数学的に重複が絶対に起こらないことを保証する仕組みではありません。取り得る値の数が非常に多いため、適切に生成すれば実務上は重複をほとんど心配しなくてよい、という性質を持っています。
1-3. Guidが使われる代表的な場面
Guidは、主に次のような場面で使われます。
データベースの主キー
ユーザーIDや会員ID
注文IDや決済ID
ファイル名の重複防止
APIリソースの識別子
ログや処理単位を追跡するためのID
分散システムにおける一意なID
Unityのアセットやゲーム内オブジェクトの識別
一時データやキャッシュのキー
たとえば画像をアップロードするとき、元のファイル名をそのまま保存すると、別の利用者が同名ファイルをアップロードした際に上書きされる恐れがあります。
そこで、次のようにGuidを含むファイル名へ変更します。
profile_8d260cf794da40229426215563e52dc1.jpg
これにより、ファイル名の衝突を起こりにくくできます。
1-4. GuidとUUIDの違い
UUIDは「Universally Unique Identifier」の略で、標準化された一意識別子です。Guidは、主にMicrosoftの技術やWindows、.NETで使われてきた呼び方です。
実務では、GuidとUUIDはほぼ同じ種類の128ビット識別子として扱われることが多く、文字列表現も次のように共通しています。
550e8400-e29b-41d4-a716-446655440000
ただし、利用する規格のバージョン、生成方法、内部バイトの並び順、ライブラリ上の型名などには違いが生じることがあります。
C#では型名がGuidであるため、通常は次のように記述します。
C#Guid id = Guid.NewGuid();
他の言語やAPIの仕様書では、同じような値がUUIDと記載されていることがあります。外部システムと連携するときは、文字列形式やバイト順などの仕様を確認しましょう。
2. C#でGuidを使う前に知っておきたい基本
2-1. GuidはSystem.Guid構造体で扱う
C#では、GuidをSystem.Guid構造体として扱います。
C#System.Guid id = System.Guid.NewGuid();
通常のC#プロジェクトではSystem名前空間が暗黙的に読み込まれているため、次のように短く記述できます。
C#Guid id = Guid.NewGuid();
暗黙的な読み込みが無効な環境では、ファイルの先頭にusing System;を記述します。
C#using System;
Guid id = Guid.NewGuid();
Console.WriteLine(id);
Guidはクラスではなく構造体、つまり値型です。そのため、通常のGuid型変数にはnullを代入できません。
C#Guid id;
// id = null; // コンパイルエラー
nullを許可したい場合は、Guid?またはNullable<Guid>を使用します。
C#Guid? id = null;
2-2. Guidの値の形式
Guidは、一般的に32桁の16進数をハイフンで区切った形式で表示されます。
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
実際の値は次のようになります。
f3d27b2e-4e9c-4eb4-89c4-1edb13b84e38
各部分の文字数は、次のとおりです。
8桁-4桁-4桁-4桁-12桁
ハイフンを除くと、16進数32桁です。16進数では、数字の0から9と英字のaからfが使われます。
なお、Guidにはハイフンを省略した形式や、波かっこ、丸かっこで囲んだ形式もあります。用途に応じてToStringメソッドの書式指定を変更できます。
2-3. Guidは128ビットの値
Guidは128ビット、つまり16バイトの値です。
1バイトは8ビットなので、次の計算になります。
16バイト × 8ビット = 128ビット
16進数1桁は4ビットを表すため、Guidはハイフンを除いて32桁になります。
32桁 × 4ビット = 128ビット
データベースでGuidを文字列として保存すると、通常は36文字分の領域が必要です。一方、SQL Serverのuniqueidentifier型など、Guid専用の型を使えば16バイトで保存できます。
そのため、データベースに保存する場合は、特別な理由がなければ文字列型よりGuidに対応した型を選ぶのが一般的です。
2-4. Guid.Emptyとは何か
Guid.Emptyは、すべてのビットが0になっているGuidです。
文字列で表すと、次の値になります。
00000000-0000-0000-0000-000000000000
次の2つの変数には、同じ値が入ります。
C#Guid id1 = Guid.Empty;
Guid id2 = new Guid();
Console.WriteLine(id1);
Console.WriteLine(id2);
Console.WriteLine(id1 == id2); // True
Guid.Emptyは、「まだIDが設定されていない」「無効なIDである」といった状態を表すために使われることがあります。
ただし、Guid.Empty自体も有効なGuid値です。業務上の未設定値として扱う場合は、アプリケーション内でルールを統一する必要があります。
2-5. nullとGuid.Emptyの違い
nullとGuid.Emptyは同じものではありません。
nullは「値そのものが存在しない状態」です。一方、Guid.Emptyは「値は存在するが、すべて0である状態」です。
C#Guid? nullableId = null;
Guid emptyId = Guid.Empty;
Console.WriteLine(nullableId is null); // True
Console.WriteLine(emptyId == Guid.Empty); // True
通常のGuidは値型なので、nullを代入できません。
C#Guid id = Guid.Empty;
nullを扱いたい場合は、Guid?を使用します。
C#Guid? id = null;
if (id is null)
{
Console.WriteLine("IDは未設定です。");
}
Guid?では、nullとGuid.Emptyの両方が存在できます。
C#Guid? id1 = null;
Guid? id2 = Guid.Empty;
Guid? id3 = Guid.NewGuid();
両方を未設定として扱う設計も可能ですが、判定条件が複雑になります。原則として、未設定をnullで表すのか、Guid.Emptyで表すのかを決めて統一しましょう。
3. C#でGuidを生成する方法
3-1. Guid.NewGuid()で新しいGuidを生成する
C#で新しいGuidを生成するには、Guid.NewGuid()を使用します。
C#Guid id = Guid.NewGuid();
Guid.NewGuid()を呼び出すたびに、新しいGuidが生成されます。
C#Guid id1 = Guid.NewGuid();
Guid id2 = Guid.NewGuid();
Console.WriteLine(id1);
Console.WriteLine(id2);
実行結果の例は次のとおりです。
2384bf5d-6559-481a-a48b-bff7436f3073
db184e44-98b0-4298-ab88-f919a211f80d
生成される具体的な値は、実行するたびに変わります。
なお、次のコードは新しいGuidを生成していません。
C#Guid id = new Guid();
引数なしのnew Guid()で作成されるのは、Guid.Emptyと同じ値です。
00000000-0000-0000-0000-000000000000
新しい一意なIDが必要な場合は、必ずGuid.NewGuid()を使用しましょう。
3-2. 生成したGuidをコンソールに表示する
生成したGuidは、Console.WriteLineでそのまま表示できます。
C#using System;
Guid id = Guid.NewGuid();
Console.WriteLine(id);
Console.WriteLineにGuidを渡すと、内部で文字列へ変換され、標準的なハイフン付き形式で出力されます。
ラベルと一緒に表示する場合は、文字列補間を使うと読みやすくなります。
C#Guid id = Guid.NewGuid();
Console.WriteLine($"生成したGuid: {id}");
実行結果の例は次のとおりです。
生成したGuid: ae46cd36-14ed-435f-8c54-08d880f3ac3d
複数のGuidを確認したい場合は、繰り返し処理を使えます。
C#for (int i = 0; i < 5; i++)
{
Console.WriteLine(Guid.NewGuid());
}
3-3. Guidを文字列に変換する
Guidを文字列へ変換するには、ToString()を使用します。
C#Guid id = Guid.NewGuid();
string text = id.ToString();
Console.WriteLine(text);
標準では、ハイフン付きの形式に変換されます。
f3d27b2e-4e9c-4eb4-89c4-1edb13b84e38
フォーマットを指定することもできます。
C#Guid id = Guid.NewGuid();
string withHyphens = id.ToString("D");
string withoutHyphens = id.ToString("N");
Console.WriteLine(withHyphens);
Console.WriteLine(withoutHyphens);
出力例は次のとおりです。
f3d27b2e-4e9c-4eb4-89c4-1edb13b84e38
f3d27b2e4e9c4eb489c41edb13b84e38
データベースやAPIがGuid型を直接扱える場合、必要以上に文字列へ変換しないほうが、型の間違いを防ぎやすくなります。
3-4. 文字列からGuidに変換する
Guid形式の文字列をGuid型へ変換するには、Guid.Parseを使用できます。
C#string text = "550e8400-e29b-41d4-a716-446655440000";
Guid id = Guid.Parse(text);
Console.WriteLine(id);
Guid.Parseは、文字列が正しいGuid形式でない場合にFormatExceptionを発生させます。
C#string text = "invalid-guid";
Guid id = Guid.Parse(text); // FormatException
形式が正しいことが保証されている固定値や、アプリケーション内部の値を変換するときには利用できます。
外部から受け取った文字列を変換する場合は、例外を発生させずに判定できるGuid.TryParseの使用がおすすめです。
特定のフォーマットだけを許可したい場合は、Guid.ParseExactも利用できます。
C#string text = "550e8400-e29b-41d4-a716-446655440000";
Guid id = Guid.ParseExact(text, "D");
3-5. TryParseで安全にGuidへ変換する
ユーザー入力、URLパラメーター、CSV、外部APIなどから受け取った文字列は、必ず正しいGuid形式であるとは限りません。
このような場合は、Guid.TryParseを使用します。
C#string text = "550e8400-e29b-41d4-a716-446655440000";
if (Guid.TryParse(text, out Guid id))
{
Console.WriteLine($"変換成功: {id}");
}
else
{
Console.WriteLine("Guidの形式が正しくありません。");
}
変換に成功した場合はtrueが返り、outで指定した変数に変換後のGuidが代入されます。
失敗した場合はfalseが返るため、例外処理を書かなくても安全に判定できます。
C#string text = "abc";
bool success = Guid.TryParse(text, out Guid id);
Console.WriteLine(success); // False
Console.WriteLine(id); // Guid.Empty
変換に失敗したとき、out変数にはGuid.Emptyが入ります。そのため、変換結果だけを見るのではなく、必ず戻り値のtrueまたはfalseを確認してください。
フォーマットを限定する場合は、Guid.TryParseExactを利用できます。
C#bool success = Guid.TryParseExact(
"550e8400e29b41d4a716446655440000",
"N",
out Guid id
);
4. Guidの使い方と実践例
4-1. データベースの主キーとして使う
Guidは、データベースの主キーとして利用できます。
C#のモデルでは、次のようにGuid型のプロパティを定義します。
C#public class Product
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
}
新しいデータを作成するときにGuidを生成します。
C#Product product = new Product
{
Id = Guid.NewGuid(),
Name = "ノートパソコン"
};
Entity Framework CoreなどのORMを使っている場合、設定やデータベースの種類によってはIDが自動生成されることもあります。ただし、どの段階でGuidを生成するのかは、プロジェクト内で統一しておくことが重要です。
SQL Serverでは、C#のGuidは基本的にuniqueidentifier型へ対応します。
SQLCREATE TABLE Products
(
Id uniqueidentifier NOT NULL PRIMARY KEY,
Name nvarchar(100) NOT NULL
);
Guidを主キーにすると、複数のシステムで生成したデータを後から統合しやすいというメリットがあります。
一方、ランダムなGuidをクラスター化インデックスのキーにすると、ページ分割や断片化が発生しやすくなる場合があります。大量データを扱う場合は、インデックス設計も含めて検討しましょう。
4-2. ファイル名の重複防止に使う
アップロードされたファイルを元の名前のまま保存すると、同じ名前のファイルによって上書きされる可能性があります。
Guidをファイル名に含めれば、重複を防ぎやすくなります。
C#string extension = ".jpg";
string fileName = $"{Guid.NewGuid():N}{extension}";
Console.WriteLine(fileName);
出力例は次のとおりです。
31d52434b95a4dc8aeec3f883242b5a8.jpg
元のファイル名の一部を残すこともできます。
C#string originalName = "profile.jpg";
string extension = Path.GetExtension(originalName);
string fileName = $"profile_{Guid.NewGuid():N}{extension}";
ただし、利用者から受け取ったファイル名をそのままパスへ連結すると、パストラバーサルなどの問題につながる可能性があります。
保存時はPath.GetFileNameやPath.GetExtensionを使い、保存可能な拡張子を検証しましょう。Guidはファイル名の衝突を防ぐための仕組みであり、安全性検証の代わりにはなりません。
4-3. ユーザーIDや注文IDとして使う
Guidは、ユーザーIDや注文IDにも利用できます。
C#public class Order
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public DateTime OrderedAt { get; set; }
}
注文を作成するコードは次のようになります。
C#Guid userId = Guid.NewGuid();
Order order = new Order
{
Id = Guid.NewGuid(),
UserId = userId,
OrderedAt = DateTime.UtcNow
};
連番の注文IDでは、URLやAPIレスポンスから総注文数などを推測されることがあります。Guidは連番より推測されにくいため、外部公開用のIDとして使いやすいという特徴があります。
ただし、Guidを知っていることをアクセス権限の代わりにしてはいけません。
たとえば、次のURLで注文情報を表示するとします。
/orders/550e8400-e29b-41d4-a716-446655440000
Guidが推測しにくくても、ログイン中の利用者がその注文を閲覧できるかどうか、サーバー側で必ず認可チェックを行う必要があります。
4-4. APIや分散システムの識別子として使う
複数のサーバーが動作する分散システムでは、1台のデータベースから連番を発行する方法が負荷や障害の原因になることがあります。
Guidであれば、各サーバーが個別にIDを生成できます。
C#public record CreateOrderResponse(
Guid OrderId,
string Status
);
レスポンスを作成する例は次のとおりです。
C#CreateOrderResponse response = new(
OrderId: Guid.NewGuid(),
Status: "Accepted"
);
JSONでは、一般的に次のような文字列として表現されます。
JSON{
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"status": "Accepted"
}
また、一連の処理を追跡する相関IDとしても利用できます。
C#Guid correlationId = Guid.NewGuid();
Console.WriteLine(
$"CorrelationId={correlationId} 注文処理を開始しました。"
);
複数のサービスで同じ相関IDをログに記録すれば、サービスをまたいだ処理を追跡しやすくなります。
4-5. Unityやアプリ開発で一意なIDとして使う
Unityやデスクトップアプリ、モバイルアプリでも、オブジェクトやデータを識別するためにGuidを利用できます。
たとえばゲーム内アイテムに一意なIDを付ける場合は、次のように実装できます。
C#public class GameItem
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; } = string.Empty;
}
ただし、Unityのインスペクターや一部のシリアライズ機能では、Guid型をそのまま扱いにくいことがあります。その場合は、文字列として保持する方法があります。
C#public class GameItemData
{
public string Id = Guid.NewGuid().ToString();
public string Name = string.Empty;
}
利用時にGuid.TryParseで検証すれば、不正な文字列を安全に検出できます。
C#if (Guid.TryParse(itemData.Id, out Guid itemId))
{
Console.WriteLine($"アイテムID: {itemId}");
}
また、Unity自体もアセットの識別にGUIDを利用します。ただし、Unityが管理するアセットGUIDと、アプリケーション内で独自に生成するSystem.Guidは、用途を分けて考えましょう。
5. Guidはなぜ重複しないのか
5-1. Guidが重複しにくい仕組み
Guidが重複しにくい最大の理由は、利用できる値の範囲が非常に広いことです。
C#でGuid.NewGuid()を実行すると、通常は十分なランダム性を持つ情報を利用して新しい値が生成されます。
C#Guid id = Guid.NewGuid();
一般的なランダム型のUUIDでは、128ビットすべてを自由に使うわけではありません。バージョンやバリアントを表すために一部のビットが使用されますが、それでも膨大な数の組み合わせがあります。
そのため、別々のコンピューターで同時に生成しても、同じ値になる可能性は極めて低くなります。
ただし、Guidは「過去に発行された全IDを中央サーバーへ問い合わせて重複確認している」わけではありません。巨大な値空間と生成アルゴリズムによって、衝突確率を現実的に無視できるほど小さくしています。
5-2. Guidの組み合わせ数はどれくらい多いのか
128ビットの値が持つ組み合わせ数は、理論上次のとおりです。
2の128乗
およそ次の規模になります。
3.4 × 10の38乗
つまり、約340澗通りという非常に大きな数です。
実際のUUIDでは、バージョン情報などに一部のビットが使われるため、ランダムに利用できるビット数はこれより少なくなる場合があります。それでも、現実的なアプリケーションで使い切ることは困難なほど多くの組み合わせがあります。
大量にGuidを生成するときは、単純に「組み合わせ数に対して発行数が少ないから安全」と考えるだけでなく、誕生日問題の影響も考慮します。発行数が増えるほど衝突確率は上昇しますが、通常のシステム規模では依然として非常に低い確率です。
5-3. 「絶対に重複しない」と言い切れない理由
Guidには有限個の組み合わせしかないため、理論上は重複する可能性があります。
同じ生成アルゴリズムで作成された2つのGuidが、偶然同じ値になる可能性はゼロではありません。
また、偶然以外にも次のような原因で重複することがあります。
同じGuidを誤って複数回保存した
固定値をコピーしたまま使用した
Guid.NewGuid()ではなくGuid.Emptyを登録したテストデータのIDを使い回した
データ移行時に既存IDを重複登録した
不適切な独自生成処理を使用した
IDの文字列を途中で切り詰めた
実務で起こる重複は、ランダム生成の偶然よりも、実装ミスや運用ミスによるものが多いと考えられます。
したがって、Guidを使っているからといって、データベースの一意制約を省略してよいわけではありません。
5-4. 実務上は重複をほぼ心配しなくてよい理由
適切なAPIを使ってGuidを生成していれば、一般的な業務システムで偶然の重複を心配する必要はほとんどありません。
C#Guid id = Guid.NewGuid();
独自の乱数処理を作るより、標準のGuid.NewGuid()を利用することが重要です。
たとえば、次のように短い乱数だけからIDを作ると、値の範囲が小さくなり、重複しやすくなります。
C#// 一意なIDの生成方法としては不適切
Random random = new Random();
int id = random.Next(1000, 9999);
4桁の数値は9,000通りしかないため、データ件数が増えると簡単に重複します。
Guidは非常に広い値空間を利用するため、標準的な生成方法を使う限り、通常のアプリケーションでは十分な一意性を得られます。
5-5. 重複が発生した場合に備えるべきケース
重複確率が低くても、重複時に重大な障害が起きるシステムでは、データベース側に一意制約を設定しましょう。
SQLCREATE TABLE Orders
(
Id uniqueidentifier NOT NULL PRIMARY KEY,
UserId uniqueidentifier NOT NULL
);
主キーやUNIQUE制約を設定しておけば、同じGuidを誤って登録しようとしたときにデータベースが拒否します。
アプリケーション側では、一意制約違反を適切に処理します。
C#Guid id = Guid.NewGuid();
try
{
// データベースへ登録する処理
}
catch (Exception ex)
{
// 実際には利用中のDBライブラリに応じて
// 一意制約違反だけを判定する
Console.WriteLine(ex.Message);
}
特に、決済、在庫、認証、医療情報など、重複による影響が大きいシステムでは、次の対策を組み合わせることが重要です。
Guidを標準APIで生成する
データベースに主キーまたはUNIQUE制約を設定する
登録処理をトランザクションで管理する
重複エラー発生時の処理を決めておく
同じ要求の二重処理を防ぐ仕組みを用意する
Guidの一意性と、業務処理の二重実行防止は別の問題です。同じリクエストが2回送信されれば、異なるGuidを持つ重複注文が作成される可能性もあります。必要に応じて冪等性キーなどを導入しましょう。
6. Guidの文字列フォーマット
6-1. 通常のGuid文字列形式
Guid.ToString()を引数なしで呼び出すと、通常はD形式の文字列になります。
C#Guid id = Guid.NewGuid();
Console.WriteLine(id.ToString());
出力例は次のとおりです。
550e8400-e29b-41d4-a716-446655440000
この形式は32桁の16進数を4本のハイフンで区切った、合計36文字の形式です。
API、ログ、設定ファイル、画面表示などでは、この標準形式を使うと他のシステムとの互換性を保ちやすくなります。
6-2. ToString("N")でハイフンなしにする
ハイフンを除いた32文字の形式にしたい場合は、ToString("N")を使用します。
C#Guid id = Guid.Parse(
"550e8400-e29b-41d4-a716-446655440000"
);
string text = id.ToString("N");
Console.WriteLine(text);
出力結果は次のとおりです。
550e8400e29b41d4a716446655440000
ファイル名、キャッシュキー、HTML要素のIDなど、区切り文字を含めたくない場面で便利です。
C#string fileName = $"{Guid.NewGuid():N}.dat";
文字列補間では、変数名の後ろにコロンと書式を指定できます。
C#Guid id = Guid.NewGuid();
Console.WriteLine($"{id:N}");
6-3. ToString("D")の使い方
D形式は、ハイフン付きの標準的な形式です。
C#Guid id = Guid.Parse(
"550e8400-e29b-41d4-a716-446655440000"
);
Console.WriteLine(id.ToString("D"));
出力結果は次のとおりです。
550e8400-e29b-41d4-a716-446655440000
引数なしのToString()と同じ形式です。
C#Console.WriteLine(id.ToString());
Console.WriteLine(id.ToString("D"));
APIでGuidを文字列として送る場合や、人がログを確認する場合は、区切り位置がわかりやすいD形式が適しています。
6-4. ToString("B")やToString("P")の違い
B形式では、Guidが波かっこで囲まれます。
C#Console.WriteLine(id.ToString("B"));
出力結果は次のとおりです。
{550e8400-e29b-41d4-a716-446655440000}
P形式では、丸かっこで囲まれます。
C#Console.WriteLine(id.ToString("P"));
出力結果は次のとおりです。
(550e8400-e29b-41d4-a716-446655440000)
X形式では、各要素を16進数として明示した特殊な形式になります。
C#Console.WriteLine(id.ToString("X"));
X形式は通常のAPIやデータベース操作で使う機会が少ないため、特別な連携仕様がない限り、DまたはNを使えば十分です。
6-5. 用途別におすすめのフォーマット
用途ごとの一般的な選び方は次のとおりです。
| 用途 | おすすめ | 特徴 |
|---|---|---|
| APIやJSON | D形式 | 標準的で読みやすい |
| ログ | D形式 | 区切りがあり確認しやすい |
| ファイル名 | N形式 | ハイフンがなく扱いやすい |
| キャッシュキー | N形式 | 短く単純な形式 |
| Windows系の設定 | B形式 | 波かっこが必要な仕様で利用 |
| 特殊なシステム連携 | 相手の仕様に合わせる | 形式の確認が必要 |
APIの入出力形式は、途中で変更すると利用者に影響します。最初にD形式などへ統一し、仕様書へ明記しましょう。
また、データベースにGuid専用型がある場合は、表示用フォーマットへ変換せず、Guid型のまま保存するのがおすすめです。
7. Guidを比較・判定する方法
7-1. Guid同士を比較する
Guid同士が同じ値かどうかは、==演算子で比較できます。
C#Guid id1 = Guid.NewGuid();
Guid id2 = id1;
Console.WriteLine(id1 == id2); // True
異なるかどうかは、!=演算子で判定できます。
C#Guid id1 = Guid.NewGuid();
Guid id2 = Guid.NewGuid();
if (id1 != id2)
{
Console.WriteLine("異なるGuidです。");
}
Equalsメソッドを使用することもできます。
C#bool same = id1.Equals(id2);
通常の等価比較では、==を使うと簡潔です。
Nullable Guidを比較する場合も、==を利用できます。
C#Guid? id1 = null;
Guid? id2 = null;
Console.WriteLine(id1 == id2); // True
7-2. Guid.Emptyかどうかを判定する
Guidが未設定値として扱っているGuid.Emptyかどうかは、次のように判定します。
C#Guid id = Guid.Empty;
if (id == Guid.Empty)
{
Console.WriteLine("IDが設定されていません。");
}
Equalsでも判定できます。
C#if (id.Equals(Guid.Empty))
{
Console.WriteLine("空のGuidです。");
}
フォームやAPIから受け取ったIDを処理する前に、Guid.Emptyを拒否する例は次のとおりです。
C#static void ValidateId(Guid id)
{
if (id == Guid.Empty)
{
throw new ArgumentException(
"IDを指定してください。",
nameof(id)
);
}
}
ただし、Guid.Emptyを未設定として扱うかどうかはアプリケーションの設計次第です。未設定を明確に表したい場合は、Guid?のnullを使う方法もあります。
7-3. 文字列のGuidが正しい形式か判定する
文字列がGuidとして正しい形式か確認するには、Guid.TryParseを使います。
C#string input =
"550e8400-e29b-41d4-a716-446655440000";
if (Guid.TryParse(input, out Guid id))
{
Console.WriteLine($"有効なGuidです: {id}");
}
else
{
Console.WriteLine("Guidの形式が正しくありません。");
}
Guid.TryParseは、複数の一般的なフォーマットを受け付けます。
D形式だけを許可したい場合は、Guid.TryParseExactを使います。
C#bool isValid = Guid.TryParseExact(
input,
"D",
out Guid id
);
さらに、Guid.Emptyを無効としたい場合は、変換成功後に追加判定します。
C#bool isValid =
Guid.TryParse(input, out Guid id) &&
id != Guid.Empty;
7-4. 大文字・小文字の違いは問題になるのか
Guidの16進数部分では、大文字と小文字は同じ値として扱われます。
次の2つは同じGuidです。
550E8400-E29B-41D4-A716-446655440000
550e8400-e29b-41d4-a716-446655440000
C#で比較すると、同じ値になります。
C#Guid upper = Guid.Parse(
"550E8400-E29B-41D4-A716-446655440000"
);
Guid lower = Guid.Parse(
"550e8400-e29b-41d4-a716-446655440000"
);
Console.WriteLine(upper == lower); // True
一方、Guidを文字列のまま比較すると、比較方法によっては大文字と小文字が異なる文字として判定されます。
C#string upper =
"550E8400-E29B-41D4-A716-446655440000";
string lower =
"550e8400-e29b-41d4-a716-446655440000";
Console.WriteLine(upper == lower); // False
Guidの同一性を判定するときは、文字列のまま比較するのではなく、Guid型へ変換して比較する方法が安全です。
7-5. Guidをソートするときの注意点
GuidにはCompareToメソッドがあるため、並べ替えること自体は可能です。
C#List<Guid> ids =
[
Guid.NewGuid(),
Guid.NewGuid(),
Guid.NewGuid()
];
ids.Sort();
ただし、ランダムに生成されたGuidを並べても、一般的には作成日時順にはなりません。
C#Guid first = Guid.NewGuid();
Thread.Sleep(100);
Guid second = Guid.NewGuid();
この2つを並べ替えても、firstが必ず先になるとは限りません。
作成日時順に表示したい場合は、Guidとは別に日時を保存します。
C#public class Record
{
public Guid Id { get; set; }
public DateTime CreatedAt { get; set; }
}
C#List<Record> sorted = records
.OrderBy(record => record.CreatedAt)
.ToList();
また、.NET、データベース、文字列比較では、Guidの並び順が一致しない場合があります。並び順に業務的な意味を持たせる設計は避け、日時や連番など、目的に合った専用列を用意しましょう。
8. Guidを使うメリット
8-1. サーバーに問い合わせずIDを生成できる
Guidは、アプリケーション内で生成できます。
C#Guid id = Guid.NewGuid();
連番IDの場合、一般的にはデータベースへ登録して初めてIDが確定します。一方、Guidはデータベースへ保存する前にIDを確定できます。
C#Guid orderId = Guid.NewGuid();
Order order = new Order
{
Id = orderId
};
これにより、保存前のデータを関連付けたり、オフライン環境でIDを発行したりできます。
複数サーバーが存在する場合でも、ID発行専用サーバーを用意せずに各サーバーで生成できる点が大きなメリットです。
8-2. 複数システム間でもIDが衝突しにくい
支店ごと、端末ごと、サービスごとにデータを生成する場合、単純な連番では同じIDが発行されることがあります。
東京システムの注文ID:1001
大阪システムの注文ID:1001
後からデータを統合すると、IDが衝突します。
Guidを使えば、それぞれのシステムが独立してIDを生成しても衝突しにくくなります。
東京:63701ea5-ebae-4689-95b4-8b1692e08825
大阪:327e0948-d85b-4252-8551-306a8a22d5d6
マイクロサービス、データ同期、オフラインアプリ、複数拠点のシステムなどで特に有効です。
8-3. 連番IDより推測されにくい
連番IDをURLに使うと、前後の番号を推測されやすくなります。
/users/1001
/users/1002
/users/1003
Guidは値が長くランダム性があるため、連番より推測されにくい形式です。
/users/550e8400-e29b-41d4-a716-446655440000
ただし、推測されにくいことと、安全にアクセスを制御できることは別です。
Guidが漏えいする可能性はあります。ログ、ブラウザー履歴、メール、Referer、画面共有などから知られることもあるため、機密データへのアクセスでは必ず認証と認可を実装してください。
8-4. ファイル名や一時IDの生成に便利
Guidはファイル名や一時データの識別子を簡単に作成できます。
C#string tempFileName =
$"{Guid.NewGuid():N}.tmp";
一時ディレクトリと組み合わせる場合は、次のように記述できます。
C#string path = Path.Combine(
Path.GetTempPath(),
$"{Guid.NewGuid():N}.tmp"
);
HTML要素などのIDにも利用できます。
C#string elementId =
$"dialog-{Guid.NewGuid():N}";
ただし、Guidを使用しても、ファイルがすでに存在しないことを理論上完全には保証できません。重要な処理では、既存ファイルを上書きしない作成方法や、ファイルシステム側の排他制御も利用しましょう。
8-5. 実装がシンプルで初心者でも扱いやすい
Guidの生成には、複雑な設定や外部ライブラリが必要ありません。
C#Guid id = Guid.NewGuid();
文字列への変換も簡単です。
C#string text = id.ToString();
文字列からの安全な変換も、標準メソッドで実装できます。
C#if (Guid.TryParse(text, out Guid parsedId))
{
Console.WriteLine(parsedId);
}
生成、変換、比較、判定に必要な機能がSystem.Guidにそろっているため、初心者でも比較的扱いやすい型です。
9. Guidを使うデメリットと注意点
9-1. 値が長くて読みづらい
Guidの標準文字列は36文字あります。
550e8400-e29b-41d4-a716-446655440000
連番IDと比べると、人が覚えたり口頭で伝えたりするのは困難です。
12345
管理画面や問い合わせ対応で利用者にIDを伝えてもらう場合、長いGuidは扱いにくくなります。
このような場合は、内部IDとしてGuidを使い、利用者向けには別の短い管理番号を用意する方法があります。
C#public class Order
{
public Guid Id { get; set; }
public string OrderNumber { get; set; } = string.Empty;
}
内部ID:550e8400-e29b-41d4-a716-446655440000
注文番号:ORD-20260611-00125
内部の一意性と、人にとっての使いやすさを分けて設計できます。
9-2. データベースのインデックス効率に影響することがある
ランダムなGuidをデータベースのクラスター化インデックスへ追加すると、既存データの途中に挿入されることがあります。
連番IDは通常、末尾へ順番に追加されます。
1001
1002
1003
1004
一方、ランダムなGuidには値の順序と生成順の関係がありません。大量の挿入が発生すると、ページ分割やインデックス断片化が起き、書き込み性能や保存効率へ影響する場合があります。
対策としては、次のような方法があります。
クラスター化インデックスには連番列を使う
Guidには非クラスター化の一意インデックスを設定する
順序性を持つGuidの採用を検討する
データベース側の連続的なGuid生成機能を検討する
定期的にインデックスを保守する
最適な方法は、使用するデータベース、データ件数、読み書きの割合によって異なります。小規模なシステムでは問題にならないこともありますが、大量データを扱う場合は性能検証が必要です。
9-3. URLに使うと長くなりやすい
GuidをURLに含めると、URLが長くなります。
https://example.com/orders/550e8400-e29b-41d4-a716-446655440000
複数のGuidや追加パラメーターを含めると、さらに長くなります。
ハイフンを省略したN形式を使えば4文字短くできます。
C#string path = $"/orders/{orderId:N}";
ただし、一般的なGuid文字列であることがわかりにくくなる場合があります。外部公開APIでは互換性や可読性を優先し、標準のD形式を使うことも多いです。
URLを短くすることが重要なサービスでは、Guidとは別に短い公開IDを発行する設計も検討しましょう。
9-4. セキュリティ目的だけで使うのは危険
Guidは推測しにくい値ですが、パスワードや認可機能の代わりにはなりません。
次のような実装は危険です。
C#// IDを知っていれば誰でも情報を取得できる設計
Order? order = await db.Orders.FindAsync(orderId);
return order;
ログイン中の利用者が、その注文を閲覧する権限を持つか確認する必要があります。
C#Order? order = await db.Orders
.SingleOrDefaultAsync(order =>
order.Id == orderId &&
order.UserId == currentUserId
);
また、一般的な識別用Guidを次の用途へ安易に使わないようにしましょう。
パスワード
暗号鍵
長期間有効な認証トークン
パスワードリセット用トークン
セッション保護を目的とした秘密値
セキュリティ用トークンには、用途に合った暗号学的に安全な生成方法、十分な長さ、有効期限、失効処理などが必要です。
9-5. 本当に連番IDではなくGuidを使うべきか考える
Guidには多くのメリットがありますが、すべてのシステムで最適とは限りません。
1台のデータベースだけで動作し、IDを外部に公開せず、データの統合予定もない場合は、intやlongの連番で十分なことがあります。
一方、次の条件がある場合はGuidが有力です。
複数サーバーでIDを生成する
オフラインでもデータを作成する
複数システムのデータを統合する
保存前にIDを確定したい
外部公開用IDを連番にしたくない
流行や習慣だけで決めず、システムの規模、性能、運用、外部公開の有無に合わせて選びましょう。
10. Guidと連番IDの違い
10-1. Guidとint型の連番IDの比較
Guidとint型の連番IDには、次のような違いがあります。
| 比較項目 | Guid | int型の連番 |
|---|---|---|
| サイズ | 16バイト | 4バイト |
| 表示 | 長い | 短い |
| 発行場所 | アプリ側でも生成可能 | 主にDB側 |
| 分散生成 | 得意 | 工夫が必要 |
| 推測しやすさ | 比較的推測しにくい | 推測しやすい |
| インデックス | ランダム値では不利な場合がある | 連続追加に向く |
| 人による確認 | 難しい | 容易 |
| システム統合 | 衝突しにくい | 衝突対策が必要 |
long型の連番を使う場合は8バイトです。それでもGuidの16バイトより小さく、インデックスもコンパクトにできます。
どちらが優れているかではなく、用途に合っているかどうかが重要です。
10-2. Guidが向いているケース
Guidは、次のようなケースに向いています。
複数のサーバーで同時にIDを発行する
マイクロサービス間でデータをやり取りする
複数拠点のデータを後から統合する
オフラインアプリでデータを生成する
データベースへ保存する前にIDが必要
外部公開するIDを連番にしたくない
ファイル名の重複を避けたい
処理を追跡する相関IDが必要
たとえば、クライアント側で親データと子データを作成してから、まとめてサーバーへ送信する場合に便利です。
C#Guid orderId = Guid.NewGuid();
Order order = new Order
{
Id = orderId
};
OrderItem item = new OrderItem
{
Id = Guid.NewGuid(),
OrderId = orderId
};
データベースへ保存する前でも関連付けを確定できます。
10-3. 連番IDが向いているケース
連番IDは、次のようなケースに向いています。
1つのデータベースでIDを一元管理できる
高い書き込み性能が重要
インデックスサイズを小さくしたい
IDを人が確認することが多い
データを生成順に並べたい
外部へIDを公開しない
シンプルな業務システムを構築する
C#のモデルでは、次のように定義します。
C#public class Category
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
データ件数がintの上限へ達する可能性がある場合は、longを検討します。
ただし、注文番号などの業務上の番号と、データベース内部の連番主キーを同一にする必要はありません。変更可能な業務番号とは別に、内部主キーを持つ設計もよく使われます。
10-4. データベース設計での使い分け
データベース設計では、Guidか連番のどちらか一方だけを選ばなければならないとは限りません。
次のように、内部主キーと公開IDを分ける方法があります。
C#public class Customer
{
public long Id { get; set; }
public Guid PublicId { get; set; }
public string Name { get; set; } = string.Empty;
}
Id:データベース内部の主キーPublicId:URLやAPIで使用する公開用ID
SQLの例は次のとおりです。
SQLCREATE TABLE Customers
(
Id bigint IDENTITY(1, 1) NOT NULL PRIMARY KEY,
PublicId uniqueidentifier NOT NULL UNIQUE,
Name nvarchar(100) NOT NULL
);
この設計では、連番のインデックス効率とGuidの推測されにくさを組み合わせられます。
ただし、列やインデックスが増えるため、ストレージ使用量や実装の複雑さも増えます。要件に必要な場合だけ採用しましょう。
10-5. 初心者が迷ったときの判断基準
初心者がGuidと連番で迷った場合は、次の基準で考えると判断しやすくなります。
1つのデータベースで完結し、IDを外部公開しない単純なアプリでは、まず連番IDを検討します。
C#public int Id { get; set; }
複数の端末やサーバーが独立してデータを作る場合は、Guidを検討します。
C#public Guid Id { get; set; }
外部公開IDを連番にしたくない一方で、データベース性能も重視する場合は、内部連番と公開Guidを分ける方法があります。
C#public long Id { get; set; }
public Guid PublicId { get; set; }
重要なのは、「Guidのほうが高度だから使う」のではなく、分散生成やデータ統合など、Guidが解決する課題があるかどうかです。
11. C# Guidでよくあるエラーと対処法
11-1. 文字列からGuidへの変換でエラーになる
Guid.Parseへ不正な文字列を渡すと、FormatExceptionが発生します。
C#string input = "12345";
Guid id = Guid.Parse(input);
ユーザー入力や外部データを扱う場合は、Guid.TryParseを使用しましょう。
C#if (!Guid.TryParse(input, out Guid id))
{
Console.WriteLine("正しいGuidを入力してください。");
return;
}
空文字列やnullも変換に失敗します。
C#string? input = null;
bool success = Guid.TryParse(input, out Guid id);
Console.WriteLine(success); // False
APIでは、不正な形式に対して400 Bad Requestを返すなど、入力エラーとして処理するのが一般的です。
11-2. Guid.Emptyのまま登録してしまう
Guid型のプロパティを初期化しない場合、既定値はGuid.Emptyです。
C#public class User
{
public Guid Id { get; set; }
}
C#User user = new User();
Console.WriteLine(user.Id);
// 00000000-0000-0000-0000-000000000000
複数データをGuid.Emptyのまま登録すると、主キーや一意制約の違反が発生します。
対策として、プロパティの初期値でGuidを生成できます。
C#public class User
{
public Guid Id { get; set; } = Guid.NewGuid();
}
または、データ作成時に明示的に設定します。
C#User user = new User
{
Id = Guid.NewGuid()
};
データベースやORMに生成を任せる場合は、アプリ側の生成と二重にならないよう設定を確認してください。
11-3. Nullable<Guid>の扱いで迷う
Guid?は、Guidまたはnullを保持できます。
C#Guid? id = null;
値があるかどうかは、HasValueまたはパターンマッチングで確認できます。
C#if (id.HasValue)
{
Console.WriteLine(id.Value);
}
より簡潔に書く場合は、次のようにします。
C#if (id is Guid value)
{
Console.WriteLine(value);
}
nullのときにValueへアクセスすると、InvalidOperationExceptionが発生します。
C#Guid? id = null;
// Guid value = id.Value; // 例外
既定値を取得するには、GetValueOrDefaultや??を使えます。
C#Guid value1 = id.GetValueOrDefault();
Guid value2 = id ?? Guid.Empty;
ただし、nullを自動的にGuid.Emptyへ変換すると、「値がない状態」と「空のGuid」が区別できなくなります。業務上の意味を確認してから変換しましょう。
11-4. データベースのuniqueidentifier型との対応
SQL Serverでは、C#のGuidは基本的にuniqueidentifier型へ対応します。
C#public Guid Id { get; set; }
SQLId uniqueidentifier NOT NULL
SQLへ値を渡すときは、可能な限り文字列へ変換せず、Guid型のパラメーターとして渡します。
C#command.Parameters.Add(
"@Id",
SqlDbType.UniqueIdentifier
).Value = id;
文字列連結でSQLを組み立てる方法は、形式エラーやSQLインジェクションなどの原因になります。
C#// 避けるべき例
string sql =
$"SELECT * FROM Users WHERE Id = '{id}'";
パラメーターを利用してください。
C#string sql =
"SELECT * FROM Users WHERE Id = @Id";
MySQLやPostgreSQLなどでは、対応する型や保存方法が異なる場合があります。利用しているデータベースとドライバーの仕様を確認しましょう。
11-5. JSONやAPIでGuidを扱うときの注意点
ASP.NET CoreとSystem.Text.Jsonでは、Guidプロパティは一般的に標準的な文字列としてJSONへ変換されます。
C#public record UserResponse(
Guid Id,
string Name
);
JSONの例は次のとおりです。
JSON{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "山田太郎"
}
受信した値が不正な形式であれば、モデルバインディングやデシリアライズでエラーになることがあります。
Nullableにするかどうかも、API仕様へ影響します。
C#public Guid Id { get; set; }
この場合、値が指定されなかったときにGuid.Emptyになる可能性があります。
C#public Guid? Id { get; set; }
こちらでは、未指定をnullとして表現できます。
API設計では、次の点を明確にしましょう。
Guidのフォーマット
大文字と小文字の扱い
nullを許可するかGuid.Emptyを許可するか不正な形式で返すステータスコード
URL、本文、ヘッダーのどこで受け取るか
Guidを文字列として受け取る設計もできますが、その場合はGuid.TryParseによる明示的な検証が必要です。
12. C# Guidのよくある質問
12-1. Guid.NewGuid()は毎回違う値になるのか
Guid.NewGuid()を呼び出すたびに、新しいGuidが生成されます。
C#Guid id1 = Guid.NewGuid();
Guid id2 = Guid.NewGuid();
Console.WriteLine(id1);
Console.WriteLine(id2);
Console.WriteLine(id1 == id2);
通常、比較結果はFalseになります。
ただし、Guidは有限個の値であるため、理論上は同じ値が生成される可能性を完全には否定できません。適切な環境で標準APIを使用している限り、実務上の衝突確率は極めて低いと考えられます。
なお、変数へ保存したGuidを何度表示しても値は変わりません。
C#Guid id = Guid.NewGuid();
Console.WriteLine(id);
Console.WriteLine(id);
新しい値が生成されるのは、Guid.NewGuid()を新たに呼び出したときです。
12-2. Guidは本当に重複しないのか
Guidは「絶対に重複しない値」ではありません。理論上は重複する可能性があります。
しかし、利用できる組み合わせが非常に多いため、標準的な方法で生成したGuidが偶然衝突する確率は極めて低くなります。
実務では、偶然の衝突よりも次のような実装ミスに注意すべきです。
C#// 毎回同じ値になる
Guid id = Guid.Empty;
C#// 固定値を使い回している
Guid id = Guid.Parse(
"550e8400-e29b-41d4-a716-446655440000"
);
新しいIDが必要な場合は、Guid.NewGuid()を使用します。
C#Guid id = Guid.NewGuid();
さらに、データベースへ主キーやUNIQUE制約を設定し、万一の重複や実装ミスを検出できるようにしましょう。
12-3. GuidとUUIDは同じものなのか
GuidとUUIDは、実務上ほぼ同じ種類の128ビット識別子として扱われます。
Microsoftや.NETではGuidという名前が使われ、他の言語やシステムではUUIDという名前が使われることが多くあります。
C#Guid id = Guid.NewGuid();
この値をAPIで送信すると、Java、Python、JavaScriptなどの別システム側でUUIDとして扱える場合があります。
ただし、バージョン、文字列形式、バイト配列への変換方法、並び順には違いが生じる可能性があります。
文字列形式で連携する場合は、標準的なハイフン付き形式を使うと互換性を確保しやすくなります。
550e8400-e29b-41d4-a716-446655440000
バイナリ形式で連携する場合は、内部のバイト順を必ず確認しましょう。
12-4. Guidは文字列として保存してもよいのか
Guidを文字列として保存することは可能です。
C#string id = Guid.NewGuid().ToString();
ただし、データベースにGuid専用型がある場合は、原則として専用型を使うほうが適しています。
文字列保存には、次のデメリットがあります。
保存領域が増えやすい
インデックスが大きくなる
不正な文字列を保存できてしまう
大文字・小文字やハイフン有無が混在する
比較や変換が必要になる
SQL Serverでは、uniqueidentifier型を利用できます。
文字列として保存する必要がある場合は、フォーマットと長さを統一しましょう。
C#string id = Guid.NewGuid().ToString("D");
たとえばD形式なら36文字、N形式なら32文字です。
設定ファイルやJSON、CSVなど、Guid専用型を持たない形式では、文字列として保存するのが一般的です。
12-5. Guidを短くする方法はあるのか
ハイフンを除くだけであれば、N形式を使って36文字から32文字に短縮できます。
C#string shortText = Guid.NewGuid().ToString("N");
さらに短く表現する方法として、16バイトのGuidをBase64へ変換する方法があります。
C#Guid id = Guid.NewGuid();
string base64 = Convert
.ToBase64String(id.ToByteArray())
.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
Console.WriteLine(base64);
この方法では、通常22文字程度のURLセーフな文字列になります。
元のGuidへ戻すには、置換とパディングを元に戻します。
C#static Guid DecodeGuid(string value)
{
string base64 = value
.Replace('-', '+')
.Replace('_', '/');
base64 += value.Length % 4 switch
{
2 => "==",
3 => "=",
_ => string.Empty
};
byte[] bytes = Convert.FromBase64String(base64);
if (bytes.Length != 16)
{
throw new FormatException(
"Guidとして不正な長さです。"
);
}
return new Guid(bytes);
}
ただし、この短縮形式は標準的なGuid文字列ではありません。外部システムと連携する場合は、エンコード方法を共通仕様として定める必要があります。
また、Guid文字列の先頭数文字だけを使う方法は避けましょう。
C#// 一意性が大幅に低下するため非推奨
string shortId = Guid.NewGuid()
.ToString("N")[..8];
文字数を切り詰めると組み合わせ数が減り、重複しやすくなります。短いIDが必要な場合は、必要な発行件数と許容できる衝突確率を考慮し、用途に合ったID方式を選びましょう。
まとめ
C#のGuidは、データやオブジェクトを一意に識別するための128ビット値です。System.Guid構造体として提供されており、次のコードで簡単に生成できます。
C#Guid id = Guid.NewGuid();
文字列から安全に変換するときは、Guid.TryParseを使用します。
C#if (Guid.TryParse(input, out Guid id))
{
Console.WriteLine(id);
}
Guidの主なメリットは、サーバーやデータベースへ問い合わせずに生成でき、複数のシステム間でも衝突しにくいことです。データベースの主キー、ユーザーID、注文ID、ファイル名、API、分散システムなど、幅広い用途で利用できます。
一方で、値が長いことや、ランダムなGuidをデータベースのインデックスへ使用すると性能に影響する場合があることには注意が必要です。また、Guidは推測されにくいだけであり、認証や認可の代わりにはなりません。
Guidと連番IDのどちらを使うか迷った場合は、複数システムでのID生成やデータ統合が必要ならGuid、単一データベースで性能や人による扱いやすさを重視するなら連番を基本に検討するとよいでしょう。
最後に、Guidを安全に利用するための要点を整理します。
新しいIDは
Guid.NewGuid()で生成するnew Guid()はGuid.Emptyになることを理解する外部文字列は
Guid.TryParseで検証するデータベースには主キーやUNIQUE制約を設定する
専用型がある場合は文字列ではなくGuid型で保存する
Guidだけに頼らず、認証と認可を実装する
作成日時順に並べる場合は日時列を別に用意する
短縮のために安易に文字列を切り詰めない
これらの基本を押さえれば、C#のGuidをさまざまなアプリケーションで正しく活用できます。

