我有一些带有计算字段的模型可以正常显示值,但是当我尝试编辑条目或创建新条目时,我得到NullReferenceException。
型号:
public class MMSPostage
{
public int ID { get; set; }
[Display(Name = "Pieces")]
public int PieceCount { get; set; }
[DisplayFormat(DataFormatString = "{0:C3}")]
public decimal Rate { get; set; }
[DisplayFormat(DataFormatString = "{0:C3}")]
[Display(Name = "Total")]
public decimal MMSSubTotal
{
get
{
return (Rate + JobType.Cost) * PieceCount;
}
}
public JobType JobType { get; set; }
}
保存时包含以下内容的编辑页面抛出NullReferenceException:
MMSPostage = await _context.MMSPostage
.Include(m => m.JobType)
.SingleOrDefaultAsync(m => m.ID == id);
上下文模型:
modelBuilder.Entity("SPM_Postage_Billing.Models.MMSPostage", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("PieceCount");
b.Property<decimal>("Rate");
b.HasKey("ID");
b.HasIndex("JobTypeID");
b.ToTable("MMSPostage");
});
SQL:
CONSTRAINT [FK_MMSPostage_JobType_JobTypeID] FOREIGN KEY ([JobTypeID]) REFERENCES [dbo].[JobType] ([ID]) ON DELETE SET DEFAULT
GO
CREATE NONCLUSTERED INDEX [IX_MMSPostage_JobTypeID]
ON [dbo].[MMSPostage]([JobTypeID] ASC);
错误:
SPM_Postage_Billing.Models.MMSPostage.get_MMSSubTotal()in MMSPostage.cs + return(Rate + JobType.Cost)* PieceCount; Microsoft.Extensions.Internal.PropertyHelper.CallNullSafePropertyGetter(Func getter,object target)
希望我能忽略一些简单的事情。我是AspNetCore的新手,所以任何帮助都很受欢迎!
答案 0 :(得分:0)
如果JobType
和MMSPostage
之间的关系只是一对多,即1 MMSPostage
有1 JobType
而1 JobType
有很多MMSPostage
,然后您可以设置如下:
注意:强>
Microsoft.EntityFrameworkCore
v2.0.3。对于延迟加载功能的v2.1.x,实体可能看起来不同,因为您可能需要virtual
关键字。namespace DL.SO.Persistence.EFCore.Entities
{
public class JobTypeEntity
{
public int Id { get; set; }
public string Name { get; set; }
public double Cost { get; set; }
public List<MMSPostageEntity> MMSPostages { get; set; }
}
}
namespace DL.SO.Persistence.EFCore.Entities
{
public MMSPostageEntity
{
public int Id { get; set; }
public int PieceCount { get; set; }
public double Rate { get; set; }
public int JobTypeId { get; set; }
public JobTypeEntity JobType { get; set; }
public double SubTotal
{
get
{
return (Rate + JobType.Cost) * PieceCount;
}
}
}
}
然后,您需要使用Data Annotations或Fluent API将实体属性配置为SQL表列。你可以直接在OnModelCreating()
上直接进行,也可以为每个实体创建配置类并在那里应用配置。
namespace DL.SO.Persistence.EFCore.Configurations
{
public class JobTypeConfiguration : IEntityTypeConfiguration<JobTypeEntity>
{
public void Configure<EntityTypeBuilder<JobTypeEntity> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).IsRequired();
builder.HasIndex(x => x.Name).IsUnique();
builder.Property(x => x.Cost).IsRequired();
builder.ToTable("JobType");
}
}
}
namespace DL.SO.Persistence.EFCore.Configurations
{
public class MMSPostageConfiguration : IEntityTypeConfiguration<MMSPostageEntity>
{
public void Configure<EntityTypeBuilder<MMSPostageEntity> builder)
{
builder.HasKey(x => x.Id);
// By default, public properties with getter and setter
// will be included!
// Since the computed property SubTotal only has getter,
// it should not be included by default.
// Just in case you worry about, you can do Ignore() too!
builder.Ignore(x => x.SubTotal);
// This is how you configure the 1-to-many relationship!
builder.HasOne(x => x.JobType)
.WithMany(jt => jt.MMSPostages)
.HasForeignKey(x => x.JobTypeId);
builder.ToTable("MMSPostage");
}
}
}
namespace DL.SO.Persistence.EFCore
{
public class AppDbContext : DbContext
{
public class AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// You apply those configurations
builder.ApplyConfiguration(new JobTypeConfiguration());
builder.ApplyConfiguration(new MMSPostageConfiguration());
}
public DbSet<JobTypeEntity> JobTypes { get; set; }
public DbSet<MMSPostageEntity> MMSPostages { get; set; }
}
}
然后在您的编辑页面上,您应该能够从数据库中获取MMSPostageEntity
,包括JobTypeEntity
,并为其构建视图模型。
namespace DL.SO.Web.UI.Controllers
{
public class PostageController : Controller
{
private readonly AppDbContext _dbContext;
public PostageController(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public IActionResult Edit(int id)
{
var postageEntity = _dbContext.MMSPostages
.AsNoTracking()
.Include(x => x.JobType)
.SingleOrDefault(x => x.Id == id);
if (postageEntity == null)
{
return NotFound();
}
// Then you can construct your view model here!
// Don't send your db entities directly to views man!
var vm = new EditPostageViewModel
{
PostageId = postageEntity.Id,
PieceCount = postageEntity.PieceCount,
Rate = postageEntity.Rate,
SubTotal = postageEntity.SubTotal,
JobType = postageEntity.JobType.Name
};
return View(vm);
}
}
}
免责声明:我手工编写了所有内容,因此未经过测试,甚至可能无法编译。