This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Saturday, 06 December 2025
केआईओस्लेव का lवां विस्तार आपको डाटाबेस- इनतम शक्तिओं के साथ भौतिक पथ देता है: BAR_ seepe इंडेक्स, विशिष्ट ऑपरेटर जैसे @> और <@, और शक्तिशाली पैटर्न मेल खाता है. यदि आप उपयोग कर रहे हैं तो सबसे अच्छा अनुक्रमीय प्रश्न प्रदर्शन करना चाहते हैं, एल ट्री को हरा करना मुश्किल है.
खुशखबरी: वह Npeglfl clfer प्रदाता LINON प्रक्रिया के लिए अनुवाद समर्थन देता है के द्वारा LTree क़िस्म. आप ऐसे तरीके इस्तेमाल कर सकते हैं IsAncestorOf(), IsDescendantOf(), और MatchesLQuery() सीधे LNEQ. हालांकि, EF कोर अब तक पुनरावर्ती सीटीएस का समर्थन नहीं करता, तो आप आपरेशन के लिए रॉ एसक्यूएल की आवश्यकता होगी जो उन्हें आवश्यक है (जैसे कि पूर्णतः निर्माण परिणाम हिसाब के साथ पूरा करें)
इन्हें धन्यवाद शैतान रोजेव्स्की एलईएसई अनुवाद समर्थन को इंगित करने के लिए!
ltree एक एसक्यूएल एक्सटेंशन है जो कि स्थानीय डाटा क़िस्म प्रदान करता है कंटूर लेबल पथों के लिए. इसके बारे में सोचो भौतिकीकृत पथ सुपर शक्तियों के साथ - डाटाबेस संरचना को समझता है और डेविडित ऑपरेटरों, कार्यों, और गीटीओ सूची समर्थन प्रदान करता है ।
पथ को गूंगा स्ट्रिंग की तरह बर्ताव करने के बजाय और चरनी की तरह इस्तेमाल करने के बजाय, एसक्यूएल यह कर सकता है:
@> के लिए "यह" का पूर्वज है, <@ "के वंश" के लिएTop.*.Europe)मुख्य अन्तर्दृष्टि: LONTE का सबसे अच्छा तरीका है - डाटाबेस-nonpon के साथ भौतिक पथों की सरलता. व्यापार बंद है, और जबकि LINQ द्वारा कई lOTOTON के काम में अब भी विभिन्न एसक्यूएल की आवश्यकता होती है.
पथ इंच पसंदीदा और लेबल:
Top.Countries.Europe.UK
Top.Countries.Asia.Japan.Tokyo
Top.Products.Electronics.Computers.Laptops
नियम:
टिप्पणी तंत्रों के लिए, हम लेबलों के रूप में आईडी का उपयोग करेंगे: 1.3.7 मतलब "एक टिप्पणी 3 के अंतर्गत 7" टिप्पणी 1 के अंदर.
पहला, एक्सटेंशन सक्षम करें (अनुप्रयोग डाटाबेस सुपरउपयोक्ता विशेषाधिकार):
CREATE EXTENSION IF NOT EXISTS ltree;
या ऐफेंस उत्प्रवासन के द्वारा:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("CREATE EXTENSION IF NOT EXISTS ltree");
}
एनजागजेजेजेसी प्रदाता शामिल करता है LTree उस नक्शे को सीधे वेब साइट में ले जाया गया और LONICONC- tolsol के तरीके प्रदान करता है:
using Microsoft.EntityFrameworkCore;
public class Comment
{
public int Id { get; set; }
public string Content { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public int PostId { get; set; }
public BlogPost Post { get; set; } = null!;
// ========== LTREE PATH ==========
// The hierarchical path in ltree format
// Format: ancestor1.ancestor2.thisNode
// Examples:
// Root comment: "1"
// Child of 1: "1.5"
// Grandchild: "1.5.12"
//
// Using the LTree type enables LINQ translations for ltree operators
public LTree Path { get; set; }
// Keep ParentCommentId for convenience
public int? ParentCommentId { get; set; }
public Comment? ParentComment { get; set; }
public ICollection<Comment> Children { get; set; } = new List<Comment>();
// ========== HELPER METHODS ==========
// Helper to get depth - LTree has NLevel property for this
public int GetDepth() => Path.NLevel - 1;
public IEnumerable<int> GetAncestorIds()
{
var pathString = Path.ToString();
if (string.IsNullOrEmpty(pathString)) yield break;
var parts = pathString.Split('.');
// All except last (which is this node)
for (int i = 0; i < parts.Length - 1; i++)
{
if (int.TryParse(parts[i], out var id))
yield return id;
}
}
}
public class CommentConfiguration : IEntityTypeConfiguration<Comment>
{
public void Configure(EntityTypeBuilder<Comment> builder)
{
builder.HasKey(c => c.Id);
builder.Property(c => c.Content)
.IsRequired()
.HasMaxLength(10000);
builder.Property(c => c.Author)
.IsRequired()
.HasMaxLength(200);
// ========== PATH COLUMN ==========
// The LTree type is automatically mapped to PostgreSQL's ltree type
// by the Npgsql provider - no explicit column type needed
builder.Property(c => c.Path)
.IsRequired();
// Relationship to blog post
builder.HasOne(c => c.Post)
.WithMany(p => p.Comments)
.HasForeignKey(c => c.PostId)
.OnDelete(DeleteBehavior.Cascade);
// Self-referencing
builder.HasOne(c => c.ParentComment)
.WithMany(c => c.Children)
.HasForeignKey(c => c.ParentCommentId)
.OnDelete(DeleteBehavior.Restrict);
// Standard indexes
builder.HasIndex(c => c.PostId);
builder.HasIndex(c => c.ParentCommentId);
}
}
उत्प्रवासन के द्वारा GiB इंडेक्स जोड़ें:
protected override void Up(MigrationBuilder migrationBuilder)
{
// GiST index for ltree - enables efficient @>, <@, and ~ operators
migrationBuilder.Sql(
"CREATE INDEX ix_comments_path_gist ON comments USING GIST (path)");
// Alternative: B-tree index for exact match and sorting
// migrationBuilder.Sql(
// "CREATE INDEX ix_comments_path_btree ON comments USING BTREE (path)");
}
एलआई- ट्री शक्तिशाली ऑपरेटर प्रदान करता है. Npegl Apl Carvel CL CONK समर्थन LTree इन ऑपरेटरों के तरीके:
INBIOWNYELLKLLLLLLLLLLYELLOCYEAL( 2000) मोड एसक्यूएल उदाहरण
|----------|---------|-------------|-------------|
| @> लुइस एक पिता है (घरों) (स्कास) ltree1.IsAncestorOf(ltree2) | '1.3'::ltree @> '1.3.7'::ltree धन - दौलत और ऐशो - आराम की चीज़ें
| <@ आग्रहीता का वंशज (परेडेड) तिबिरियास ltree1.IsDescendantOf(ltree2) | '1.3.7'::ltree <@ '1.3'::ltree धन - दौलत और ऐशो - आराम की चीज़ें
| ~ आपसी मेल - जोल ltree.MatchesLQuery(pattern) | '1.3.7'::ltree ~ '1.*'::lquery धन - दौलत और ऐशो - आराम की चीज़ें
| @ आपसी मेल - जोल ltree.MatchesLTxtQuery(query) | '1.3.7'::ltree @ '3 & 7'::ltxtquery धन - दौलत और ऐशो - आराम की चीज़ें
| || कंटीपरेशन पथ (साइम्पेक्टीशन इस्तेमाल करें) (g)unit-format '1.3'::ltree || '7'::ltree → '1.3.7' |
| <, >, <=, >= STATEX मानक ऑपरेटरो के लिए छंटाई के लिए मौजूद है
अतिरिक्त LNONEQCKtable गुण तथा विधियाँ:
ltree.NLevel → nlevel(ltree) - पथ में लेबलों की संख्याltree.Subtree(start, end) → subltree(ltree, start, end) - लेबलों की सीमा निकाली जा रही हैltree.Subpath(offset) → subpath(ltree, offset) - ऑफसेट से प्रत्ययltree.Subpath(offset, len) → subpath(ltree, offset, len) - सबस्ट्रिंगltree.Index(subpath) → index(ltree, subpath) - उपपथ स्थिति ढूंढा जा रहा हैLTree.LongestCommonAncestor(ltree1, ltree2) → lca(ltree1, ltree2) - कम से कम सामान्य पूर्वजpublic async Task<Comment> AddCommentAsync(
int postId,
int? parentId,
string author,
string content,
CancellationToken ct = default)
{
string path;
if (parentId.HasValue)
{
// Get parent's path
var parentPath = await context.Comments
.Where(c => c.Id == parentId.Value)
.Select(c => c.Path)
.FirstOrDefaultAsync(ct);
if (parentPath == null)
throw new InvalidOperationException($"Parent comment {parentId} not found");
// Create comment first to get the ID
var comment = new Comment
{
PostId = postId,
ParentCommentId = parentId,
Author = author,
Content = content,
CreatedAt = DateTime.UtcNow,
Path = string.Empty // Temporary
};
context.Comments.Add(comment);
await context.SaveChangesAsync(ct);
// Build path: parentPath.newId
// ltree uses periods as separators
comment.Path = $"{parentPath}.{comment.Id}";
await context.SaveChangesAsync(ct);
logger.LogInformation("Added comment {CommentId} with ltree path {Path}",
comment.Id, comment.Path);
return comment;
}
else
{
// Root comment - path is just the ID
var comment = new Comment
{
PostId = postId,
ParentCommentId = null,
Author = author,
Content = content,
CreatedAt = DateTime.UtcNow,
Path = string.Empty
};
context.Comments.Add(comment);
await context.SaveChangesAsync(ct);
comment.Path = comment.Id.ToString();
await context.SaveChangesAsync(ct);
return comment;
}
}
अभिभावक उपयोग किया जा रहा हैComment
public async Task<List<Comment>> GetChildrenAsync(int commentId, CancellationToken ct = default)
{
// Option 1: Simple ParentCommentId lookup
return await context.Comments
.AsNoTracking()
.Where(c => c.ParentCommentId == commentId)
.OrderBy(c => c.CreatedAt)
.ToListAsync(ct);
}
// Option 2: Using ltree pattern (demonstration)
public async Task<List<Comment>> GetChildrenLtreeAsync(int commentId, CancellationToken ct = default)
{
// Get parent path first
var parentPath = await context.Comments
.Where(c => c.Id == commentId)
.Select(c => c.Path)
.FirstOrDefaultAsync(ct);
if (parentPath == null)
return new List<Comment>();
// Children match pattern: parentPath.*{1}
// The {1} means exactly one more label (immediate children only)
var sql = @"
SELECT * FROM comments
WHERE path ~ ($1 || '.*{1}')::lquery
ORDER BY created_at";
return await context.Comments
.FromSqlRaw(sql, parentPath)
.AsNoTracking()
.ToListAsync(ct);
}
LONQ का प्रयोग कर रहा है IsAncestorOf विधि (परलेट्स) @> ऑपरेटरः
public async Task<List<Comment>> GetAncestorsAsync(int commentId, CancellationToken ct = default)
{
var targetPath = await context.Comments
.Where(c => c.Id == commentId)
.Select(c => c.Path)
.FirstOrDefaultAsync(ct);
if (targetPath == default)
return new List<Comment>();
// Find all nodes whose path is an ancestor of this path
// Using IsAncestorOf which translates to @> operator
return await context.Comments
.AsNoTracking()
.Where(c => c.Path.IsAncestorOf(targetPath) && c.Id != commentId)
.OrderBy(c => c.Path.NLevel)
.ToListAsync(ct);
}
LONQ का प्रयोग कर रहा है IsDescendantOf विधि (परलेट्स) <@ ऑपरेटरः
public async Task<List<Comment>> GetDescendantsAsync(int commentId, CancellationToken ct = default)
{
var parentPath = await context.Comments
.Where(c => c.Id == commentId)
.Select(c => c.Path)
.FirstOrDefaultAsync(ct);
if (parentPath == default)
return new List<Comment>();
// Find all nodes whose path is a descendant of this path
// Using IsDescendantOf which translates to <@ operator
return await context.Comments
.AsNoTracking()
.Where(c => c.Path.IsDescendantOf(parentPath) && c.Id != commentId)
.OrderBy(c => c.Path)
.ToListAsync(ct);
}
LINQ का प्रयोग कर रहा है NLevel गहराई सीमित करने के लिए:
public async Task<List<Comment>> GetDescendantsToDepthAsync(
int commentId,
int maxDepth,
CancellationToken ct = default)
{
var comment = await context.Comments
.FirstOrDefaultAsync(c => c.Id == commentId, ct);
if (comment == null)
return new List<Comment>();
var basePath = comment.Path;
var baseLevel = comment.Path.NLevel;
// NLevel property translates to nlevel() function
// Filter descendants within maxDepth levels
return await context.Comments
.AsNoTracking()
.Where(c => c.Path.IsDescendantOf(basePath)
&& c.Id != commentId
&& c.Path.NLevel - baseLevel <= maxDepth)
.OrderBy(c => c.Path)
.ToListAsync(ct);
}
// If you need the depth value in results, you can project it:
public async Task<List<CommentWithDepth>> GetDescendantsWithDepthAsync(
int commentId,
int maxDepth,
CancellationToken ct = default)
{
var comment = await context.Comments
.FirstOrDefaultAsync(c => c.Id == commentId, ct);
if (comment == null)
return new List<CommentWithDepth>();
var basePath = comment.Path;
var baseLevel = comment.Path.NLevel;
return await context.Comments
.AsNoTracking()
.Where(c => c.Path.IsDescendantOf(basePath)
&& c.Id != commentId
&& c.Path.NLevel - baseLevel <= maxDepth)
.OrderBy(c => c.Path)
.Select(c => new CommentWithDepth
{
Id = c.Id,
Content = c.Content,
Author = c.Author,
CreatedAt = c.CreatedAt,
PostId = c.PostId,
ParentCommentId = c.ParentCommentId,
Path = c.Path.ToString(),
Depth = c.Path.NLevel - baseLevel
})
.ToListAsync(ct);
}
एलआई- ट्री समर्थन शक्तिशाली lquery पैटर्न को समर्थन देता है. इस्तेमाल करें MatchesLQuery एलईएसईसी में:
// Find all comments at exactly depth 2 under comment 1
public async Task<List<Comment>> GetAtDepthAsync(int commentId, int depth, CancellationToken ct = default)
{
var path = await context.Comments
.Where(c => c.Id == commentId)
.Select(c => c.Path)
.FirstOrDefaultAsync(ct);
if (path == default) return new List<Comment>();
// Pattern: path.*{depth} matches exactly 'depth' more levels
var pattern = $"{path}.*{{{depth}}}";
return await context.Comments
.AsNoTracking()
.Where(c => c.Path.MatchesLQuery(pattern))
.OrderBy(c => c.Path)
.ToListAsync(ct);
}
// Find all paths matching a pattern like "1.*.7" (any path through 1 ending in 7)
public async Task<List<Comment>> MatchPatternAsync(string pattern, CancellationToken ct = default)
{
// MatchesLQuery translates to the ~ operator
return await context.Comments
.AsNoTracking()
.Where(c => c.Path.MatchesLQuery(pattern))
.OrderBy(c => c.Path)
.ToListAsync(ct);
}
आप LINONQ का उपयोग सब ट्री को चुनने के लिए कर सकते हैं, फिर मिटा सकते हैं:
public async Task DeleteSubtreeAsync(int commentId, CancellationToken ct = default)
{
var path = await context.Comments
.Where(c => c.Id == commentId)
.Select(c => c.Path)
.FirstOrDefaultAsync(ct);
if (path == default)
throw new InvalidOperationException($"Comment {commentId} not found");
// Delete all descendants (nodes where path is descendant of this path)
// Note: ExecuteDeleteAsync requires EF Core 7+
var deleted = await context.Comments
.Where(c => c.Path.IsDescendantOf(path))
.ExecuteDeleteAsync(ct);
logger.LogInformation("Deleted {Count} comments with path prefix {Path}", deleted, path);
}
गलत इस्तेमाल के लिए मदद के लिए आई- ट्री फंक्शन प्रदान करता है:
public async Task MoveSubtreeAsync(
int commentId,
int newParentId,
CancellationToken ct = default)
{
await using var transaction = await context.Database.BeginTransactionAsync(ct);
try
{
var node = await context.Comments.FirstOrDefaultAsync(c => c.Id == commentId, ct);
var newParent = await context.Comments.FirstOrDefaultAsync(c => c.Id == newParentId, ct);
if (node == null || newParent == null)
throw new InvalidOperationException("Node or parent not found");
// Prevent cycles
if (newParent.Path.StartsWith(node.Path))
throw new InvalidOperationException("Cannot move under own descendant");
var oldPath = node.Path;
var newPath = $"{newParent.Path}.{node.Id}";
// Update all descendants: replace old path prefix with new one
// subpath(path, nlevel(oldPath)) gets the suffix after oldPath
// We concatenate newPath with that suffix
var sql = @"
UPDATE comments
SET path = $2::ltree || subpath(path, nlevel($1::ltree))
WHERE path <@ $1::ltree";
await context.Database.ExecuteSqlRawAsync(
sql,
new object[] { oldPath, newPath },
ct);
// Update parent reference
node.ParentCommentId = newParentId;
await context.SaveChangesAsync(ct);
await transaction.CommitAsync(ct);
logger.LogInformation("Moved subtree from {OldPath} to {NewPath}", oldPath, newPath);
}
catch
{
await transaction.RollbackAsync(ct);
throw;
}
}
एसक्यूएल बहुत से उपयोगी आई- ट्री फ़ंक्शन प्रदान करता है:
IMSINEP विवरणE (एक्सटीक उदाहरण)
|----------|-------------|---------|
| nlevel(ltree) बाक़ी लेबलों की संख्या nlevel('1.3.7') → 3 |
| subpath(ltree, offset) ऑफसेट (L) subpath('1.3.7', 1) → '3.7' |
| subpath(ltree, offset, len) IMS सबस्ट्रिंग subpath('1.3.7', 1, 1) → '3' |
| subltree(ltree, start, end) ख़ुदा की आयतों की समाप्ति subltree('1.3.7', 0, 2) → '1.3' |
| lca(ltree, ltree) [ पेज 23 पर बड़े अक्षरों में लेख की खास बात] lca('1.3.7', '1.3.9') → '1.3' |
| text2ltree(text) INBOX को पाठ में बदलें text2ltree('1.3.7') |
| ltree2text(ltree) Ublh ट्री को पाठ गुनाह पर बदलें ltree2text('1.3.7'::ltree) |
sequenceDiagram
participant App as Application
participant EF as EF Core
participant PG as PostgreSQL + ltree
Note over App,PG: Getting Descendants (GiST index)
App->>EF: GetDescendantsAsync(commentId)
EF->>PG: SELECT path FROM comments WHERE id = @id
PG-->>EF: Path "1.3"
EF->>PG: SELECT * FROM comments WHERE path <@ '1.3'::ltree
Note over PG: Uses GiST index - O(log n)
PG-->>EF: All descendants
EF-->>App: List<Comment>
Note over App,PG: Pattern Match Query
App->>EF: MatchPatternAsync("1.*.7")
EF->>PG: SELECT * FROM comments WHERE path ~ '1.*.7'::lquery
Note over PG: GiST index supports pattern matching
PG-->>EF: Matching comments
EF-->>App: List<Comment>
INRE ऑपरेशन सामग्री जटिलता नोट्स |-----------|------------|-------| IMTARICO( 1) सिर्फ पथ वाक्यांश 6 सेट करता है IMTALOO( 1) पैटर्न TBBICOLLLLLL के साथ मेल खाता है IMTAN( 1) पितरों प्राप्त करें O( 1) @> ऑपरेटर GSBT अनुक्रमणिका के साथ IMTALONTOO( 1) < seBT इंडेक्स के साथ ऑपरेटर Libisofs पैटर्न से मेल खाता है IMSURTINTH O( s) COSKRियन पथ पथ यहूदियों के लिए अद्यतन किया जा रहा है INBOSTHOOOL < > चयन के लिए ऑपरेटर को मिटाएँ
GiB इंडेक्स्स के साथ, ब्लू ट्रीज अति कुशल हैं - विशेष रूप से ओ(L), फिर भी पेड़ गहराई के बावजूद ।
आपसी रिश्तों में दरार
|------|------|
IMDICKS डाटाबेस- इनकॉम्पैक्ट- सिर्फ उन्हीं के लिए है
सभी डाटा- सूची के लिए गीत- सूची
1440 शक्तिशाली पैटर्नmahjongg map name
INVECKICKL को रॉ एसक्यूएल लानत की आवश्यकता है
IMTARO पिता / SERTCT CONT TAN को शुद्ध एएफ कोर समाधान से कम
कॉम्पैक्ट भंडार (C)
सीजेके एलईएसईसी समर्थन नेक्खिलल के द्वारा LTree type- जिनको तुम चाहो, उन्हीं के हाथ में रखो, और उन्हें मालूम हो जाएगा कि वे किस प्रकार चल रहे हैं
जब: (o)
जब: (o)
ACTATAT Abltip path path path
|--------|-------------------|-------|
INBICONT सूची क़िस्म B- folder (सिर्फprewit) 1998 GiB (सभी पैटर्न)
INBLTET पैटर्न जैसे 'pally' से मेल खाता है सिर्फ पूर्ण वाइल्डकार्ड्स
पारितोषिक ऑपरेटर्स
ACACKLPYEALLLLANKT( 12. 5)
INFINCKLLLLLLNKRINCKRINKRINK समर्थन LTree क़िस्म (Cases)
IMSTRIGenericName
सम्बन्धित फ़ंक्शन कुछ नहीं (मुख्य पारसिंग) बड़े-बड़े फंक्शन लाइब्रेरी
इस सब को एक साथ रखना - ब्लॉग पोस्ट के लिए गहराई के साथ एक पूरी टिप्पणी वृक्ष मिलता है:
public async Task<List<CommentTreeItem>> GetPostCommentTreeAsync(
int postId,
int maxDepth = 5,
CancellationToken ct = default)
{
// Get all comments for the post with calculated depth
// nlevel() counts the labels in the path
var sql = @"
WITH root_comments AS (
-- Find root comments for this post (no dot in path = root)
SELECT path, nlevel(path) as root_level
FROM comments
WHERE post_id = $1 AND path !~ '*.*'
)
SELECT
c.id,
c.content,
c.author,
c.created_at,
c.post_id,
c.parent_comment_id,
c.path::text as path,
nlevel(c.path) - COALESCE(
(SELECT root_level FROM root_comments r
WHERE c.path <@ r.path
ORDER BY nlevel(r.path) DESC LIMIT 1),
nlevel(c.path)
) as depth
FROM comments c
WHERE c.post_id = $1
AND nlevel(c.path) <= $2 + 1 -- +1 because depth is 0-indexed
ORDER BY c.path"; -- Perfect depth-first order!
return await context.Database
.SqlQueryRaw<CommentTreeItem>(sql, postId, maxDepth)
.ToListAsync(ct);
}
public class CommentTreeItem
{
public int Id { get; set; }
public string Content { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public int PostId { get; set; }
public int? ParentCommentId { get; set; }
public string Path { get; set; } = string.Empty;
public int Depth { get; set; }
}
इस श्रंखला ने ईएफ कोर के उपयोग से पाँच निकट आता है ।
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.