Skip to content

Commit e78a7ba

Browse files
lukemurrayclaude
andcommitted
Leave out a DbContext's own members by type, not by name on every type
IgnoreProps held Database, Model, ChangeTracker and ContextId by default, to keep an EF Core DbContext's machinery out of the schema. It matches by name on every type, so any entity property called Model (or Database, ...) was silently dropped from the schema too. Members declared on Microsoft.EntityFrameworkCore.DbContext are now left out by their declaring type, matched by name so there is still no EF reference, and IgnoreProps is empty by default. It still ignores whatever names are added to it, everywhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent dd0d510 commit e78a7ba

6 files changed

Lines changed: 69 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 6.3.0
2+
3+
## Changes
4+
5+
- `SchemaBuilderOptions.IgnoreProps` is empty by default. It held `Database`, `Model`, `ChangeTracker` and `ContextId` to keep an EF Core `DbContext`'s own members out of the schema, but it matches by name on every type, so a property called `Model` (a car's, a run's, a usage row's) was silently left out wherever it appeared. Those `DbContext` members are now left out by the type that declares them - `Microsoft.EntityFrameworkCore.DbContext`, matched by name so there is still no EF reference - and a property with one of those names on any other type is a field. A schema with such a property gains that field; to keep it out, `options.Builder.IgnoreProps.Add("Model")` (or `[GraphQLIgnore]` on the property).
6+
17
# 6.2.4
28

39
## Fixes

‎docs/docs/schema-creation/schema-creation.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public List<AllowedException> AllowedExceptions { get; set; } = [
166166
- `.AutoCreateEnumTypes` - automatically create Enum types in the schema if found in the `DemoContext` object graph. Default is `true`
167167
- `.AutoCreateNewComplexTypes` - automatically add dotnet types found in the object graph to the schema. This will also call `AddAllFields()` on those types passing this options object to it. Default is `true`
168168
- `.AutoCreateInterfaceTypes` - If true (default = false), any object type that is encountered during reflection of the object graph that has abstract or interface types (regardless of if they are referenced by other fields), those will be added to the schema as an Interface including it's fields. Note types are always linked (`implements`) to base types that are in the schema as interfaces (e.g. an abstract base class referenced by a context property) - this option only controls _creating_ interface types for base types not otherwise in the schema
169-
- `.IgnoreProps` - List properties or field names to ignore. Default includes a list of EF properties. Default list includes
169+
- `.IgnoreProps` - Property or field names to ignore on every type. Empty by default. An Entity Framework Core `DbContext`'s own members are always left out (below), by the type that declares them rather than by name, so a property with one of those names on your own types is still a field. The `DbContext` members left out are
170170

171171
```json
172172
"Database",

‎src/EntityGraphQL/Schema/SchemaBuilder.cs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,16 @@ public static List<BaseField> GetFieldsFromObject(Type type, ISchemaType fromTyp
438438
return field;
439439
}
440440

441+
/// <summary>
442+
/// EF Core's own DbContext members - Database, Model, ChangeTracker, ContextId - are its machinery,
443+
/// not data. Matched by where they are declared, so a property of the same name on an entity is
444+
/// still a field, and by type name, so EntityGraphQL needs no reference to EF.
445+
/// </summary>
446+
private static bool IsDeclaredOnDbContext(MemberInfo member) => member.DeclaringType?.FullName == "Microsoft.EntityFrameworkCore.DbContext";
447+
441448
private static bool ShouldIncludeMember(MemberInfo prop, SchemaBuilderOptions options, bool isInputType)
442449
{
443-
if (options.IgnoreProps.Contains(prop.Name) || GraphQLIgnoreAttribute.ShouldIgnoreMemberFromQuery(prop))
450+
if (IsDeclaredOnDbContext(prop) || options.IgnoreProps.Contains(prop.Name) || GraphQLIgnoreAttribute.ShouldIgnoreMemberFromQuery(prop))
444451
return false;
445452

446453
if (isInputType && GraphQLIgnoreAttribute.ShouldIgnoreMemberFromInput(prop))

‎src/EntityGraphQL/Schema/SchemaBuilderOptions.cs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ namespace EntityGraphQL.Schema;
1111
public class SchemaBuilderOptions
1212
{
1313
/// <summary>
14-
/// List properties or field names to ignore. Default includes a list of EF properties
14+
/// Property or field names to ignore, on every type. Empty by default.
15+
///
16+
/// The members of an Entity Framework Core DbContext (Database, Model, ChangeTracker, ContextId) are
17+
/// always left out, by the type that declares them rather than by name, so an entity's own property
18+
/// with one of those names is kept. Add a name here to leave it out everywhere.
1519
/// </summary>
16-
public HashSet<string> IgnoreProps { get; set; } = ["Database", "Model", "ChangeTracker", "ContextId"];
20+
public HashSet<string> IgnoreProps { get; set; } = [];
1721

1822
/// <summary>
1923
/// List of dotnet Types to ignore when adding types to the schema
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using EntityGraphQL.Schema;
2+
using Xunit;
3+
4+
namespace EntityGraphQL.EF.Tests;
5+
6+
public class DbContextMembersTests
7+
{
8+
[Fact]
9+
public void TestDbContextOwnMembersAreNotFields()
10+
{
11+
var schema = SchemaBuilder.FromObject<TestDbContext>();
12+
13+
foreach (var name in new[] { "database", "model", "changeTracker", "contextId" })
14+
Assert.False(schema.Query().HasField(name, null), $"{name} should not be in the schema");
15+
Assert.True(schema.Query().HasField("movies", null));
16+
}
17+
}

‎src/tests/EntityGraphQL.Tests/SchemaTests/SchemaBuilderFromObjectTests.cs‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,4 +593,35 @@ private class Property : IUnion
593593
{
594594
public Guid Id { get; set; }
595595
}
596+
597+
[Fact]
598+
public void TestPropertyNamedLikeADbContextMemberIsAField()
599+
{
600+
// The names IgnoreProps used to hold by default left these out of every type, not just the DbContext
601+
var schema = SchemaBuilder.FromObject<VehicleContext>();
602+
603+
Assert.True(schema.Type<Vehicle>().HasField("model", null));
604+
Assert.True(schema.Type<Vehicle>().HasField("database", null));
605+
}
606+
607+
[Fact]
608+
public void TestIgnorePropsStillIgnoresByName()
609+
{
610+
var schema = SchemaBuilder.FromObject<VehicleContext>(new SchemaBuilderOptions { IgnoreProps = ["Model"] });
611+
612+
Assert.False(schema.Type<Vehicle>().HasField("model", null));
613+
Assert.True(schema.Type<Vehicle>().HasField("database", null));
614+
}
615+
616+
private class VehicleContext
617+
{
618+
public List<Vehicle> Vehicles { get; set; } = [];
619+
}
620+
621+
private class Vehicle
622+
{
623+
public int Id { get; set; }
624+
public string Model { get; set; } = "";
625+
public string Database { get; set; } = "";
626+
}
596627
}

0 commit comments

Comments
 (0)