Skip to content

Commit 353ea69

Browse files
kawasaniacAndriySvyryd
authored andcommitted
Add helpful exception when a property’s backing field cannot be found.
Fixes #35219
1 parent 2f5c7f3 commit 353ea69

4 files changed

Lines changed: 111 additions & 76 deletions

File tree

‎src/EFCore.Design/Properties/DesignStrings.Designer.cs‎

Lines changed: 61 additions & 53 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/EFCore.Design/Properties/DesignStrings.resx‎

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@
126126
<data name="BadMigrationName" xml:space="preserve">
127127
<value>The migration name '{name}' is not valid. Migration names cannot contain any of the following characters: '{characters}'.</value>
128128
</data>
129-
<data name="MigrationNameRequired" xml:space="preserve">
130-
<value>A migration name must be specified.</value>
131-
</data>
132129
<data name="BadSequenceType" xml:space="preserve">
133130
<value>Sequence '{sequenceName}' cannot be scaffolded because it uses type '{typeName}' which is unsupported.</value>
134131
</data>
@@ -162,6 +159,9 @@
162159
<data name="CompilationMustBeLoaded" xml:space="preserve">
163160
<value>A compilation must be loaded.</value>
164161
</data>
162+
<data name="CompiledModelBackingFieldNotFound" xml:space="preserve">
163+
<value>Backing field for property '{entityType}.{propertyName}' could not be inferred. Use a matching field name or configure with 'HasField()'.</value>
164+
</data>
165165
<data name="CompiledModelConstructorBinding" xml:space="preserve">
166166
<value>The entity type '{entityType}' has a custom constructor binding. Compiled model can't be generated, because custom constructor bindings are not supported. Configure the custom constructor binding in '{customize}' in a partial '{className}' class instead.</value>
167167
</data>
@@ -193,6 +193,9 @@ Consider changing your target project to the DbContext project by using the Pack
193193
<data name="CouldNotGetInterceptableLocation" xml:space="preserve">
194194
<value>Couldn't get interceptable location for: '{node}'.</value>
195195
</data>
196+
<data name="CreatingAndApplyingMigration" xml:space="preserve">
197+
<value>Creating and applying migration '{migrationName}'.</value>
198+
</data>
196199
<data name="DatabaseDropped" xml:space="preserve">
197200
<value>Successfully dropped database '{name}'.</value>
198201
</data>
@@ -208,6 +211,9 @@ Consider changing your target project to the DbContext project by using the Pack
208211
<data name="DuplicateMigrationName" xml:space="preserve">
209212
<value>The name '{migrationName}' is used by an existing migration.</value>
210213
</data>
214+
<data name="DynamicMigrationNotFound" xml:space="preserve">
215+
<value>The dynamic migration '{migrationId}' was not found. Only migrations applied in the current session using CreateAndApplyMigration can be reverted.</value>
216+
</data>
211217
<data name="DynamicQueryNotSupported" xml:space="preserve">
212218
<value>Dynamic LINQ queries are not supported when precompiling queries.</value>
213219
</data>
@@ -289,14 +295,27 @@ Consider changing your target project to the DbContext project by using the Pack
289295
<data name="ManuallyDeleted" xml:space="preserve">
290296
<value>The model snapshot and the backing model of the last migration are different. Continuing under the assumption that the last migration was deleted manually.</value>
291297
</data>
298+
<data name="MigrationCompilationFailed" xml:space="preserve">
299+
<value>Failed to compile migration '{migrationId}'. Errors:
300+
{errors}</value>
301+
</data>
302+
<data name="MigrationCreatedAndApplied" xml:space="preserve">
303+
<value>Migration '{migrationId}' was successfully created and applied.</value>
304+
</data>
292305
<data name="MigrationDescription" xml:space="preserve">
293306
<value>The target migration. If '0', all migrations will be reverted. Defaults to the last migration.</value>
294307
</data>
308+
<data name="MigrationNameRequired" xml:space="preserve">
309+
<value>A migration name must be specified.</value>
310+
</data>
295311
<data name="MigrationsAssemblyMismatch" xml:space="preserve">
296312
<value>Your target project '{assembly}' doesn't match your migrations assembly '{migrationsAssembly}'. Either change your target project or change your migrations assembly.
297313
Change your migrations assembly by using DbContextOptionsBuilder. E.g. options.UseSqlServer(connection, b =&gt; b.MigrationsAssembly("{assembly}")). By default, the migrations assembly is the assembly containing the DbContext.
298314
Change your target project to the migrations project by using the Package Manager Console's Default project drop-down list, or by executing "dotnet ef" from the directory containing the migrations project.</value>
299315
</data>
316+
<data name="MigrationTypeNotFound" xml:space="preserve">
317+
<value>Could not find migration type with ID '{migrationId}' in the compiled assembly.</value>
318+
</data>
300319
<data name="MSBuildWorkspaceDiagnostics" xml:space="preserve">
301320
<value>MSBuild Workspace diagnostics:{diagnostics}</value>
302321
</data>
@@ -342,6 +361,9 @@ Change your target project to the migrations project by using the Package Manage
342361
<data name="NoDesignTimeServices" xml:space="preserve">
343362
<value>No design-time services were found.</value>
344363
</data>
364+
<data name="NoDynamicMigrationsToRevert" xml:space="preserve">
365+
<value>No dynamic migrations have been applied in the current session. Only migrations applied using CreateAndApplyMigration can be reverted with RevertMigration.</value>
366+
</data>
345367
<data name="NoLanguageService" xml:space="preserve">
346368
<value>The project language '{language}' isn't supported by the built-in {service} service. You can try looking for an additional NuGet package which supports this language; moving your DbContext type to a C# class library referenced by this project; or manually implementing and registering the design-time service for the programming language.</value>
347369
</data>
@@ -360,12 +382,6 @@ Change your target project to the migrations project by using the Package Manage
360382
<data name="NoPendingModelChanges" xml:space="preserve">
361383
<value>No changes have been made to the model since the last migration.</value>
362384
</data>
363-
<data name="NoDynamicMigrationsToRevert" xml:space="preserve">
364-
<value>No dynamic migrations have been applied in the current session. Only migrations applied using CreateAndApplyMigration can be reverted with RevertMigration.</value>
365-
</data>
366-
<data name="DynamicMigrationNotFound" xml:space="preserve">
367-
<value>The dynamic migration '{migrationId}' was not found. Only migrations applied in the current session using CreateAndApplyMigration can be reverted.</value>
368-
</data>
369385
<data name="NoReferencedServices" xml:space="preserve">
370386
<value>No referenced design-time services were found.</value>
371387
</data>
@@ -499,17 +515,4 @@ Change your target project to the migrations project by using the Package Manage
499515
<data name="WritingSnapshot" xml:space="preserve">
500516
<value>Writing model snapshot to '{file}'.</value>
501517
</data>
502-
<data name="MigrationCompilationFailed" xml:space="preserve">
503-
<value>Failed to compile migration '{migrationId}'. Errors:
504-
{errors}</value>
505-
</data>
506-
<data name="MigrationTypeNotFound" xml:space="preserve">
507-
<value>Could not find migration type with ID '{migrationId}' in the compiled assembly.</value>
508-
</data>
509-
<data name="CreatingAndApplyingMigration" xml:space="preserve">
510-
<value>Creating and applying migration '{migrationName}'.</value>
511-
</data>
512-
<data name="MigrationCreatedAndApplied" xml:space="preserve">
513-
<value>Migration '{migrationId}' was successfully created and applied.</value>
514-
</data>
515518
</root>

‎src/EFCore.Design/Scaffolding/Internal/CSharpRuntimeModelCodeGenerator.cs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1769,7 +1769,9 @@ private void RegisterPrivateAccessors(
17691769
Dictionary<Type, HashSet<MemberInfo>> unsafeAccessorTypes,
17701770
ref Dictionary<MemberInfo, QualifiedName>? memberAccessReplacements)
17711771
{
1772-
var member = property.GetMemberInfo(forMaterialization, forSet);
1772+
var member = property.GetMemberInfo(forMaterialization, forSet) ?? throw new InvalidOperationException(
1773+
DesignStrings.CompiledModelBackingFieldNotFound(property.DeclaringType.ShortName(), property.Name));
1774+
17731775
switch (member)
17741776
{
17751777
case FieldInfo field:
@@ -1799,6 +1801,7 @@ private void RegisterPrivateAccessors(
17991801
}
18001802

18011803
memberAccessReplacements ??= [];
1804+
18021805
var methodName = LinqToCSharpSyntaxTranslator.GetUnsafeAccessorName(member);
18031806

18041807
var declaringType = member.DeclaringType!;

‎test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Net.NetworkInformation;
1010
using System.Runtime.CompilerServices;
1111
using System.Text.Json;
12+
using Microsoft.EntityFrameworkCore.Internal;
1213
using Microsoft.EntityFrameworkCore.Metadata.Internal;
1314
using Microsoft.EntityFrameworkCore.Storage.Json;
1415
using Microsoft.EntityFrameworkCore.ValueGeneration.Internal;
@@ -1167,6 +1168,20 @@ public virtual Task ComplexTypes()
11671168
},
11681169
options: new CompiledModelCodeGenerationOptions { UseNullableReferenceTypes = true, ForNativeAot = true });
11691170

1171+
[ConditionalFact]
1172+
public virtual Task CompiledModelBackingFieldNotFound()
1173+
=> Test(
1174+
modelBuilder =>
1175+
{
1176+
modelBuilder.Entity<EntityWithNoBackingFieldCollection>(eb =>
1177+
{
1178+
eb.Property(e => e.Collection)
1179+
.UsePropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
1180+
});
1181+
},
1182+
options: new CompiledModelCodeGenerationOptions { ForNativeAot = true },
1183+
expectedExceptionMessage: DesignStrings.CompiledModelBackingFieldNotFound("EntityWithNoBackingFieldCollection", "Collection"));
1184+
11701185
protected virtual void BuildComplexTypesModel(ModelBuilder modelBuilder)
11711186
{
11721187
modelBuilder.Entity<PrincipalBase>(eb =>
@@ -1790,6 +1805,12 @@ public class Data
17901805
public byte[]? Blob { get; set; }
17911806
}
17921807

1808+
public class EntityWithNoBackingFieldCollection
1809+
{
1810+
public int Id { get; set; }
1811+
public IList<int> Collection => new List<int>();
1812+
}
1813+
17931814
public class PrincipalBase : AbstractBase
17941815
{
17951816
public new long? Id { get; set; }

0 commit comments

Comments
 (0)