Search code examples
entity-framework-coreef-core-3.1

EF Core: Lazy-loaded navigations must have backing fields


I understand, what is a backing field and work with it ten years. But really I don't see what is the mistake in the code below:

public class Cal
{
    public int ID { get; set; }
    public double? AreaSqFt { get; set; }
    public int? NumberOfPeople { get; set; }

    private ICollection<CalcOfSpaceContaminant> _сalcOfSpaceContaminants;
    public virtual ICollection<CalcOfSpaceContaminant> CalcOfSpaceContaminants { get => _сalcOfSpaceContaminants ??= new List<CalcOfSpaceContaminant>(); protected set => _сalcOfSpaceContaminants = value; }

}

public class CalcOfSpaceContaminant
{
    public int ID { get; set; }

    public double? Vr { get; set; }
    public double? Cbz { get; set; }
    public double? Fr { get; set; }

    public int CalcID { get; set; }
    public virtual Cal Cal { get; set; }
}

and mapping:

public class CalcOfSpaceContaminantMap : IEntityTypeConfiguration<CalcOfSpaceContaminant>
{
    public void Configure(EntityTypeBuilder<CalcOfSpaceContaminant> builder)
    {
        builder.ToTable(nameof(CalcOfSpaceContaminant));
        builder.HasKey(p => p.ID);

        builder.HasOne(contaminant => contaminant.Cal)
            .WithMany(cal => cal.CalcOfSpaceContaminants)
            .HasForeignKey(k => k.CalcID)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

and then

        builder.ApplyConfiguration(new CalcOfSpaceContaminantMap());

But when I try to create a migration, I receive:

No backing field was found for property 'Cal.CalcOfSpaceContaminants'. Lazy-loaded navigations must have backing fields. Either name the backing field so that it is discovered by convention or configure the backing field to use.

What is wrong here? Thanks

ADDED #1

It's not depended on ICollection because I use ICollection everywhere, e.g.:

public partial class Zone
{
    public int Id { get; set; }
    public string ZoneName { get; set; }

    private ICollection<Cal> _cals;
    public virtual ICollection<Cal> Cals { get => _cals ??= new List<Cal>(); protected set => _cals = value; }
}

public class CalMap : IEntityTypeConfiguration<Cal>
{
    public void Configure(EntityTypeBuilder<Cal> builder)
    {
        builder.ToTable(nameof(Cal));
        builder.HasKey(p => p.ID);

        builder.HasOne(p => p.Zone)
            .WithMany(z => z.Cals)
            .HasForeignKey(p => p.ZoneId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

ADDED #2

After @akseli post below I replaced cyrillic letter 'c' to latin and it works. I thought problem was in that letter, but I have the other place:

    //public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get; protected set; } = new List<DownloadCenterFile>();


    private ICollection<DownloadCenterFile> _files;
    public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get => _files ??= new List<DownloadCenterFile>(); protected set => _files = value; }

this code does not work (says similar, no backing field), but if I uncomment first line public virtual ICollection<DownloadCenterFile> DownloadCenterFiles { get; protected set; } = new List<DownloadCenterFile>(); and comment these 2 - it works. I don't see any cyrillic letters here. Seems, the problem is in my approach.


Solution

  • After reviewing your code, I realized something very strange. It seems that you have some kind of encoding issue where the c character is actually being interpreted differently.

    Below, you can see a screenshot of a simple diff, one with the code copy-pasted from here, and the other where I typed out the variable name by hand.

    As you can see, there is a difference with c. diff results of c backing field names Furthermore, copy pasting each of the c characters into a unicode character detector yields the following results: results of c character comparison

    This leads me to think that EF is unable to detect your naming conventions correctly because of the "weird" c character that changes from place to place.

    You might want to rewrite all of the code to make sure that you're getting the actually correct unicode characters everywhere you're referencing _calcOfSpaceContaminants.