我现在两次遇到这个问题,我不太明白为什么。我通过发布一个viewmodel来在我的数据库中创建一个wine。该视图模型的Wine属性已正确填充,但是当我保存数据库中的更改时,导航属性不会填充 - 就像我想的那样。我需要这个,因为我将这个wine对象传递给一个方法,将这些导航属性添加到我的搜索索引中。
我试图将数据库重新查询到一个新变量,但这也不起作用。我真的很困惑这个 - 所以任何帮助都会很棒。我遇到了一个非常类似的问题,没有收到任何答案here。其他人通过重新查询db here解决了这个问题,但这对我不起作用。该模型在GET请求中填充正常,但不在帖子上填充。
控制器:
[HttpPost]
//[Authorize(Roles = "admin, producereditor")]
public ActionResult Create(NewWineViewModel nw)
{
if (ModelState.IsValid)
{
nw.Wine.Active = nw.IsRequest ? false : true;
//keep nullable for requests.
nw.Wine.ImporterID = nw.Wine.ImporterID == 0 ? null : nw.Wine.ImporterID;
nw.Wine.VarTypeID = nw.Wine.VarTypeID == 0 ? null : nw.Wine.VarTypeID;
nw.Wine.OriginID = nw.Wine.OriginID == 0 ? null : nw.Wine.OriginID;
nw.Wine.AppID = nw.Wine.AppID == 0 ? null : nw.Wine.AppID;
nw.Wine.VintageID = nw.Wine.VintageID == 0 ? null : nw.Wine.VintageID;
nw.Wine.CreatedBy = this.User.Identity.Name;
nw.Wine.CreatedOn = DateTime.Now;
db.Wines.Add(nw.Wine);
db.SaveChanges();
var wineToIndex = db.Wines.Find(nw.Wine.WineID);
// nw.Wine.QRUrl = WineUtils.MakeQRCode(nw.Wine);
//db.SaveChanges();
//Lucene.LuceneSearch.AddUpdateLuceneIndex(db.Wines.Find(nw.Wine.WineID));
if (nw.IsRequest)
{
nw.VOAVIRequest.WineID = nw.Wine.WineID;
nw.VOAVIRequest.CreatedBy = User.Identity.Name;
nw.VOAVIRequest.CreatedOn = DateTime.Now;
db.VOAVIRequests.Add(nw.VOAVIRequest);
db.SaveChanges();
return RedirectToAction("Requested");
//redirect to "Request Submitted" page for new wines
}
return RedirectToAction("Details", new { id = nw.Wine.WineID });
}
ViewBag.VarTypeID = new SelectList(db.VarTypes, "VarTypeID", "Name").Default("Select a Varietal/Type", nw.Wine.VarTypeID.ToString());
ViewBag.OriginID = new SelectList(db.Origins, "OriginID", "Name").Default("Select an Origin", nw.Wine.OriginID.ToString());
ViewBag.AppID = new SelectList(db.Apps, "AppID", "Name").Default("Select an Appellation", nw.Wine.AppID.ToString());
ViewBag.VintageID = new SelectList(db.Vintages, "VintageID", "Name").Default("Select a Vintage", nw.Wine.VintageID.ToString());
ViewBag.ImporterID = new SelectList(db.Importers, "ImporterID", "Name").Default("Select an Importer", nw.Wine.ImporterID.ToString());
if (User.IsInRole("producer"))
{
Producer currentProd = db.ProducerUsers.Find(Membership.GetUser().ProviderUserKey).Producer;
ViewBag.ProducerID = currentProd.ProducerID;
ViewBag.ProducerName = currentProd.Name;
}
else
{
ViewBag.ProducerSelect = new SelectList(db.Producers, "ProducerID", "Name", nw.Wine.ProducerID);
}
return View(nw);
}
视图模型:
public class NewWineViewModel
{
public Wine Wine { get; set; }
public VOAVIRequest VOAVIRequest { get; set; }
public bool IsRequest { get; set; }
public SelectList VarTypes { get; set; }
public SelectList Origins { get; set; }
public SelectList Apps { get; set; }
public SelectList Vintages { get; set; }
public SelectList Importers { get; set; }
public NewWineViewModel()
{
this.Wine = new Wine();
}
}
型号:
public class Wine :Updater
{
public int WineID { get; set; }
//public int WineTypeID { get; set; }
[Display(Name = "Varietal/Type")]
public int? VarTypeID { get; set; }
[Display(Name = "Origin")]
public int? OriginID { get; set; }
[Display(Name = "Appellation")]
public int? AppID { get; set; }
[Display(Name = "Vintage")]
public int? VintageID { get; set; }
[Display(Name = "Importer")]
public int? ImporterID { get; set; }
public int ProducerID { get; set; }
public string Designate { get; set; }
[Display(Name = "Drink Window")]
public string DrinkWindow { get; set; }
public string Body { get; set; }
public string SKU { get; set; }
[Display(Name = "Varietal Makeup")]
public string VarietalMakeup { get; set; }
[Display(Name = "Case Production")]
public string CaseProduction { get; set; }
[Display(Name = "Alcohol Content")]
public double? AlcoholContent { get; set; }
public string Winemaker { get; set; }
[Display(Name = "Consulting Winemaker")]
public string ConsultWinemaker { get; set; }
public bool Sustainable { get; set; }
public bool Kosher { get; set; }
public bool Organic { get; set; }
public bool Biodynamic { get; set; }
public bool SalmonSafe { get; set; }
public Boolean Active { get; set; }
[Display(Name = "ResidualSugar")]
public double? RS { get; set; }
public double? pH { get; set; }
public string QRUrl { get; set; }
public virtual WineType WineType { get; set; }
public virtual VarType VarType { get; set; }
public virtual Origin Origin { get; set; }
public virtual App App { get; set; }
public virtual Vintage Vintage { get; set; }
public virtual Importer Importer { get; set; }
public virtual Producer Producer { get; set; }
[JsonIgnore]
public virtual ICollection<POS> POSs { get; set; }
[JsonIgnore]
public virtual ICollection<Review> Reviews { get; set; }
[JsonIgnore]
public virtual ICollection<Doc> Docs { get; set; }
[JsonIgnore]
public IEnumerable<SelectListItem> BodyList { get; set; }
答案 0 :(得分:3)
该视图模型的Wine属性已正确填充,但是当我 保存数据库中的更改,不会填充导航属性 - 就像我想的那样。
保存对数据库的更改永远不会从数据库加载数据,因此无法填充导航属性。您在这种特定情况下的期望是,延迟加载将在您访问它们时立即预测导航属性(模型中的virtual
)。这实际上是每个导航属性的单独查询。
现在,问题是延迟加载在POST操作中无效,因为模型绑定器已实例化nw.Wine
实体。但是模型绑定器(它对Entity Framework一无所知)不会为Wine实体创建延迟加载代理对象,而只使用new
(或者可能使用反射API进行一些实例化)。延迟加载代理需要延迟加载。
如果要手动创建nw.Wine
实体,可以使用...创建延迟加载代理
nw.Wine = db.Wines.Create();
...而不是使用nw.Wine = new Wine();
。您的代码将按预期工作,并且在将实体附加/添加到EF上下文后,延迟加载将填充导航属性。
您在评论中提出的解决方案......
nw.Wine.Producer = db.Producers.Find(nw.Wine.ProducerID)
在我看来,...(和其他导航属性相同)是正确的方法。或者你可以使用显式加载:
db.Entry(nw.Wine).Reference(w => w.Producer).Load();
但是所有三种情况 - 延迟加载(如果可行),使用Find
或使用显式加载 - 将执行相同的数据库查询。因此,性能方面没有区别。
您的GET操作中的延迟加载有效,因为 - 我想 - 您正在从数据库中加载葡萄酒实体...
var wine = db.Wines.Find(id); // or maybe `Single` or `First`, etc.
...并从数据库加载实体会创建一个延迟加载代理。