I've had a look around at various related questions, but can't seem to find one that helps me get my head around this one.
I've used EF Core Power Tools to set up my DbContext; one particular entity is as follows:
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace FIS2DataTables.Tables
{
[Table("Settings", Schema = "static")]
[Index(nameof(Setting), IsUnique = true)]
public partial class Settings
{
[Key]
[Column("id")]
public int Id { get; set; }
[Required]
[Column("setting")]
[StringLength(50)]
public string Setting { get; set; }
[Required]
[Column("value")]
[StringLength(200)]
public string Value { get; set; }
[Column("intValue")]
public int? IntValue { get; set; }
[Column("bitValue")]
public bool? BitValue { get; set; }
}
}
Now I have two different files that reference this particular entity. This is one of those files (simplified):
using FIS2DataTables.Context;
using FIS2DataTools.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
namespace FIS2DataTools.Services
{
public class SettingsService : ISettingsService
{
private readonly IConfiguration Configuration;
private readonly IDbContextFactory<FIS2TableContext> ContextFactory;
public SettingsService(IDbContextFactory<FIS2TableContext> contextFactory, IConfiguration configuration)
{
ContextFactory = contextFactory;
Configuration = configuration;
}
private T GetConfigSetting<T>(string toFind)
{
return Configuration.GetValue<T>(toFind);
}
private string GetDbSetting(string toFind)
{
using (FIS2TableContext context = ContextFactory.CreateDbContext())
{
return context.Settings.FirstOrDefault(x => x.Setting == toFind).Value;
}
}
private async Task<string> GetDbSettingAsync(string toFind)
{
using (FIS2TableContext context = ContextFactory.CreateDbContext())
{
return (await context.Settings.FirstOrDefaultAsync(x => x.Setting == toFind)).Value;
}
}
public string GetDomainName()
{
return GetDbSetting("DomainName");
}
public string GetPhotosPath()
{
return GetDbSetting("PhotosPath");
}
public async Task<string> GetPhotosPathAsync()
{
return await GetDbSettingAsync("PhotosPath");
}
public string GetStoragePath()
{
return GetConfigSetting<string>("StoragePaths:Local");
}
}
}
The methods in question are GetDbSetting and its async counterpart. In both methods, this block: context.Settings.FirstOrDefault(x => x.Setting == toFind) is flagged with:
Dereference of a possibly null reference
My digging around basically says that this is just the compiler's way of saying:
This might, maybe, be null at some point... I'm not sure
However... I have the exact same code elsewhere in the solution (I'm partway through migrating it from project A to B), and in that other location it doesn't flag it.
First and foremost, I'm surprised by the inconsistency of it; but moreover, I'm wondering what the best course of action to avoid this is?
EDIT: now that I've asked the question; I've realised the instance that gets flagged, is the one where I'm referencing it in a seperate project - it's not as simple as it being that tying the analyser in knots?
For reference, the the other file (the one where it doesn't get flagged) is as follows:
using FIS2DataLibrary.Data.Interfaces;
using FIS2DataLibrary.Helpers;
using FIS2DataLibrary.Tables;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Linq;
using System.Threading.Tasks;
namespace FIS2DataLibrary.Data.Services
{
public class SettingsService : ISettingsService
{
private readonly IConfiguration Configuration;
private readonly IDbContextFactory<FIS2_TableContext> ContextFactory;
public SettingsService(IDbContextFactory<FIS2_TableContext> contextFactory, IConfiguration configuration)
{
ContextFactory = contextFactory;
Configuration = configuration;
}
private T GetConfigSetting<T>(string toFind)
{
return Configuration.GetValue<T>(toFind);
}
private string GetDbSetting(string toFind)
{
using (FIS2_TableContext context = ContextFactory.CreateDbContext())
{
return context.Settings.FirstOrDefault(x => x.Setting == toFind).Value;
}
}
private async Task<string> GetDbSettingAsync(string toFind)
{
using (FIS2_TableContext context = ContextFactory.CreateDbContext())
{
return (await context.Settings.FirstOrDefaultAsync(x => x.Setting == toFind)).Value;
}
}
public string GetDomainName()
{
return GetDbSetting("DomainName");
}
public async Task<MailServerConnectionSettings> GetMailServerConnectionSettingsAsync()
{
return new MailServerConnectionSettings(await GetDbSettingAsync("MailHost"), await GetDbSettingAsync("MailUser"), await GetDbSettingAsync("MailPass"));
}
public string GetPhotosPath()
{
return GetDbSetting("PhotosPath");
}
public async Task<string> GetPhotosPathAsync()
{
return await GetDbSettingAsync("PhotosPath");
}
public string GetStoragePath()
{
return GetConfigSetting<string>("StoragePaths:Local");
}
}
}
The ONLY difference between the two is that the one that isn't flagged exists in the same solution as its version of the DbContext; whereas the version that gets flagged references the DbContext from a seperate project.
CodePudding user response:
Since the only distinction is that code resides in different projects - then the one with warning should have nullable references types enabled. Check for Nullable xml element in corresponding .csproj.
You can disable the nullable reference types or (I think better) handle potential nullability(for example by "removing" it with First if you are sure that query should always return something).
