diff --git a/src/BLite.SourceGenerators/Helpers/BLiteConventions.cs b/src/BLite.SourceGenerators/Helpers/BLiteConventions.cs
index 8b0a66f9..081ec6e3 100644
--- a/src/BLite.SourceGenerators/Helpers/BLiteConventions.cs
+++ b/src/BLite.SourceGenerators/Helpers/BLiteConventions.cs
@@ -9,8 +9,6 @@ internal static class BLiteConventions
// ── DbContext discovery ────────────────────────────────────────────────
/// Base class name that marks a user class as a BLite DbContext.
public const string DocumentDbContextBaseName = "DocumentDbContext";
- /// Suffix expected on DbContext class names to filter candidates early.
- public const string DbContextClassSuffix = "Context";
/// File suffix used to skip already-generated files.
public const string GeneratedFileSuffix = ".g.cs";
diff --git a/src/BLite.SourceGenerators/MapperGenerator.cs b/src/BLite.SourceGenerators/MapperGenerator.cs
index 7e7cfa7f..45cd94d6 100644
--- a/src/BLite.SourceGenerators/MapperGenerator.cs
+++ b/src/BLite.SourceGenerators/MapperGenerator.cs
@@ -489,13 +489,18 @@ private static void PrintNestedTypes(StringBuilder sb, Dictionary
+ /// Syntactic pre-filter: any class with a base list. Whether it really derives from
+ /// DocumentDbContext is decided semantically in .
+ /// The class name is deliberately not part of the filter: a context may be called
+ /// anything (Shop, AppDb), and a name filter would skip it silently (#300).
+ ///
private static bool IsPotentialDbContext(SyntaxNode node)
{
if (node.SyntaxTree.FilePath.EndsWith(BLiteConventions.GeneratedFileSuffix)) return false;
return node is ClassDeclarationSyntax classDecl &&
- classDecl.BaseList != null &&
- classDecl.Identifier.Text.EndsWith(BLiteConventions.DbContextClassSuffix);
+ classDecl.BaseList != null;
}
// ── Interceptor helpers ───────────────────────────────────────────────────
diff --git a/tests/BLite.Shared/UnsuffixedNameFixtures.cs b/tests/BLite.Shared/UnsuffixedNameFixtures.cs
new file mode 100644
index 00000000..a361113e
--- /dev/null
+++ b/tests/BLite.Shared/UnsuffixedNameFixtures.cs
@@ -0,0 +1,44 @@
+using BLite.Bson;
+using BLite.Core;
+using BLite.Core.Collections;
+
+namespace BLite.Shared;
+
+// Regression fixtures for EntglDb/BLite#300: the mapper generator only looked at classes
+// whose name ends in "Context", so a DocumentDbContext called anything else got no generated
+// code and no diagnostic, and its collections stayed null. These classes compiling at all
+// (InitializeCollections is generated) already proves the generator found them.
+
+/// A context whose name does not end in "Context".
+public partial class Shop : DocumentDbContext
+{
+ public DocumentCollection Customers { get; set; } = null!;
+
+ public Shop(string databasePath) : base(databasePath)
+ {
+ InitializeCollections();
+ }
+}
+
+/// A context that derives from another context, neither named with the suffix.
+public partial class OnlineShop : Shop
+{
+ public DocumentCollection Orders { get; set; } = null!;
+
+ public OnlineShop(string databasePath) : base(databasePath)
+ {
+ InitializeCollections();
+ }
+}
+
+public class ShopCustomer
+{
+ public ObjectId Id { get; set; }
+ public string Name { get; set; } = "";
+}
+
+public class ShopOrder
+{
+ public ObjectId Id { get; set; }
+ public decimal Total { get; set; }
+}
diff --git a/tests/BLite.Tests/UnsuffixedNameGeneratorTests.cs b/tests/BLite.Tests/UnsuffixedNameGeneratorTests.cs
new file mode 100644
index 00000000..cd478bde
--- /dev/null
+++ b/tests/BLite.Tests/UnsuffixedNameGeneratorTests.cs
@@ -0,0 +1,69 @@
+using BLite.Bson;
+using BLite.Shared;
+
+namespace BLite.Tests;
+
+///
+/// Regression coverage for a DocumentDbContext whose class name does not end in
+/// "Context" (see UnsuffixedNameFixtures.cs in BLite.Shared). The generator's syntax
+/// filter used to require that suffix, so such a context got no generated code and no
+/// diagnostic; its collection properties stayed null (EntglDb/BLite#300).
+///
+public class UnsuffixedNameGeneratorTests : IDisposable
+{
+ private readonly string _dbPath = Path.Combine(Path.GetTempPath(), $"blite_unsuffixed_{Guid.NewGuid():N}.db");
+
+ public void Dispose()
+ {
+ TryDelete(_dbPath);
+ TryDelete(Path.ChangeExtension(_dbPath, ".wal"));
+ }
+
+ private static void TryDelete(string path)
+ {
+ try { if (File.Exists(path)) File.Delete(path); } catch { /* best-effort */ }
+ }
+
+ [Fact]
+ public async Task Context_NamedWithoutSuffix_HasGeneratedCollections_AndRoundTrips()
+ {
+ using var db = new Shop(_dbPath);
+
+ Assert.NotNull(db.Customers);
+
+ var id = ObjectId.NewObjectId();
+ await db.Customers.InsertAsync(new ShopCustomer { Id = id, Name = "Ada" });
+
+ var stored = await db.Customers.FindByIdAsync(id);
+ Assert.NotNull(stored);
+ Assert.Equal("Ada", stored.Name);
+ }
+
+ [Fact]
+ public async Task DerivedContext_NamedWithoutSuffix_HasBothCollections()
+ {
+ using var db = new OnlineShop(_dbPath);
+
+ Assert.NotNull(db.Customers);
+ Assert.NotNull(db.Orders);
+
+ var id = ObjectId.NewObjectId();
+ await db.Orders.InsertAsync(new ShopOrder { Id = id, Total = 12.5m });
+ var stored = await db.Orders.FindByIdAsync(id);
+ Assert.NotNull(stored);
+ Assert.Equal(12.5m, stored.Total);
+ }
+
+ [Fact]
+ public void Generated_Mappers_Exist_ForTheUnsuffixedContext()
+ {
+ var mapperTypes = typeof(Shop).Assembly
+ .GetTypes()
+ // "{namespace}.{class}_{file}_Mappers", as for every context (see GlobalNamespaceGeneratorTests).
+ .Where(t => t.Namespace == $"{typeof(Shop).Namespace}.{nameof(Shop)}_UnsuffixedNameFixtures_Mappers")
+ .ToArray();
+
+ Assert.NotEmpty(mapperTypes);
+ Assert.Contains(mapperTypes, t => t.Name.Contains(nameof(ShopCustomer)));
+ }
+}