EF Core中查询取值的属性无法持久化,遇无支持字段错误
问题场景
我定义了如下实体类,想要让PrixTotaleTTc从关联的DetailsReceptionFournisseur数据计算得出,于是加了私有计算属性PrixTotaleTTc2,但运行时出现错误:
public class BonDeReceptionFournisseur { private readonly BigSoftContext bigSoftContext; public BonDeReceptionFournisseur() { } private BonDeReceptionFournisseur(BigSoftContext bigSoftContext) { this.bigSoftContext = bigSoftContext; } [Key] public int Id { get; set; } public Decimal? PrixTotaleTTc { get; set; } private Decimal? PrixTotaleTTc2 => DetailsReceptions?.Sum(x => x.MontantTTc) ?? bigSoftContext.Set<DetailsReceptionFournisseur>() .Where(x => x.IdBonReception == Id).Sum(x => x.MontantTTc) ?? 0; public Decimal? PrixTotaleHt { get; set; } public DateTime Date { get; set; } public Boolean Confirmed { get; set; } public int FournisseurId { get; set; } public virtual Fournisseur Fournisseur { get; set; } public string GrossisteId { get; set; } public virtual Grossiste Grossiste { get; set; } public virtual ICollection<DetailsReceptionFournisseur> DetailsReceptions { get; set; } public FactureFournisseur FactureFournisseur { get; set; } }
报错信息:
No backing field could be found for property 'BonDeReceptionFournisseur.PrixTotaleTTc2' and the property does not have a setter.
问题原因
EF Core会自动扫描实体类的所有属性(包括私有属性),尝试将其映射到数据库表的字段。但PrixTotaleTTc2是只读的计算属性,既没有对应的数据库字段,也没有后备字段(backing field),EF Core无法识别它的用途,因此抛出错误。
解决方案
方案1:让EF忽略该私有属性
在你的DbContext的OnModelCreating方法中,明确配置EF不要映射这个私有属性:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 直接用属性名称字符串指定忽略的私有属性 modelBuilder.Entity<BonDeReceptionFournisseur>() .Ignore("PrixTotaleTTc2"); }
这样EF就不会再尝试处理这个属性,报错自然消失。
方案2:直接改造目标属性PrixTotaleTTc
既然原本的需求就是让PrixTotaleTTc成为计算值,直接把计算逻辑移到这个公共属性上,同时用[NotMapped]标记它不需要数据库映射:
// 标记该属性不对应数据库字段 [NotMapped] public Decimal? PrixTotaleTTc => DetailsReceptions?.Sum(x => x.MontantTTc) ?? bigSoftContext.Set<DetailsReceptionFournisseur>() .Where(x => x.IdBonReception == Id).Sum(x => x.MontantTTc) ?? 0;
这样就不需要额外的私有属性,直接实现需求,同时避免EF的映射问题。
方案3:使用数据库计算列(可选)
如果希望这个总和由数据库自动计算并存储,可以配置EF将PrixTotaleTTc映射为数据库计算列(需数据库支持,如SQL Server):
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<BonDeReceptionFournisseur>() .Property(b => b.PrixTotaleTTc) .HasComputedColumnSql("(SELECT COALESCE(SUM(MontantTTc), 0) FROM DetailsReceptionFournisseur WHERE IdBonReception = Id)"); }
这种方式下,属性可以保留常规的getter/setter(或者只读),EF会自动识别它是数据库计算生成的字段。
内容的提问来源于stack exchange,提问作者Houssem Nabouli

