C#中DbContext查询返回Null但数据库有数据,求问题排查
问题分析与解决:EF Core泛型转换导致返回Null的问题
问题重现
用户提供的API端点代码:
[HttpGet("{language}")] public async Task<IActionResult> GetAllClozeWords(string language) { var clozes = await GetClozesForLanguage<Cloze>(language); if (clozes.IsNullOrEmpty()) { return BadRequest(); } return Ok(); } private async Task<List<T>> GetClozesForLanguage<T>(string language) where T : Cloze { switch (language.ToLower()) { case "nl": return await this._trackerDbContext.NLclozes.ToListAsync() as List<T>; case "en": return await this._trackerDbContext.ENclozes.ToListAsync() as List<T>; default: return new List<T>(); } }
对应的EF实体模型:
public abstract class Cloze { public int Id { get; set; } public string cloze_word { get; set; } } public class NLcloze : Cloze { public string note1 { get; set; } public string note2 { get; set; } public string note3 { get; set; } public virtual ICollection<NLexpression> NLexpressions { get; set; } public virtual ICollection<ENcloze> ENclozes { get; set; } } public class ENcloze : Cloze { public string note1 { get; set; } public string note2 { get; set; } public string note3 { get; set; } public virtual ICollection<ENexpression> ENexpressions { get; set; } public virtual ICollection<NLcloze> NLclozes { get; set; } }
调用端点传入nl参数时,GetClozesForLanguage<Cloze>返回结果始终为Null,尽管数据库存在对应数据。
问题原因
核心问题出在as List<T>的类型转换逻辑:
- 调用
GetClozesForLanguage<Cloze>时,泛型参数T为抽象基类Cloze _trackerDbContext.NLclozes.ToListAsync()返回的是List<NLcloze>类型List<T>是不变泛型类型,即便NLcloze继承自Cloze,List<NLcloze>也无法直接转换为List<Cloze>,as转换会返回Null
解决方案
将as List<T>替换为显式的元素类型转换,利用Cast<T>方法逐个将子类实例转换为基类类型:
修改后的GetClozesForLanguage方法:
private async Task<List<T>> GetClozesForLanguage<T>(string language) where T : Cloze { switch (language.ToLower()) { case "nl": var nlClozes = await this._trackerDbContext.NLclozes.ToListAsync(); return nlClozes.Cast<T>().ToList(); case "en": var enClozes = await this._trackerDbContext.ENclozes.ToListAsync(); return enClozes.Cast<T>().ToList(); default: return new List<T>(); } }
补充优化:原API端点的Ok()未返回查询到的clozes数据,建议修改为return Ok(clozes);,否则前端无法获取具体内容。
内容的提问来源于stack exchange,提问作者aldo
相关产品推荐
相关产品推荐

