C# 查看模型虚拟属性和下拉列表
我很难掌握正确的方法来创建视图模型并使用Entity Framework将信息保存回数据库,而且我似乎找不到我要查找的信息,因此如果我忽略了它,请原谅我 我看到这篇帖子,他似乎在问同样的问题,但没有得到答案 我的主要问题是, 出于编辑目的,如果我有一个C# 查看模型虚拟属性和下拉列表,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我很难掌握正确的方法来创建视图模型并使用Entity Framework将信息保存回数据库,而且我似乎找不到我要查找的信息,因此如果我忽略了它,请原谅我 我看到这篇帖子,他似乎在问同样的问题,但没有得到答案 我的主要问题是, 出于编辑目的,如果我有一个产品模型具有保修模型关系,我是应该在视图模型中使用虚拟财产保修,还是应该使用int保修ID? 如果我应该使用虚拟财产,为什么此代码不能正确保存保修? 我是否需要明确标记或填充保修以进行更新? 请注意,这不会按预期填充我的编辑视图和选择列表 我的(简
产品模型
具有保修模型
关系,我是应该在视图模型中使用虚拟财产保修
,还是应该使用int保修ID
?
如果我应该使用虚拟财产,为什么此代码不能正确保存保修
?
我是否需要明确标记或填充保修以进行更新?
请注意,这不会按预期填充我的编辑视图和选择列表
我的(简化)代码设置如下:
型号:
public int ModelId{ get; set; }
public int ModelNumber { get; set; }
public virtual Warranty Warranty { get; set;}
视图模型:
public int ModelId { get; set; }
[Required(ErrorMessage = "Model Number required")]
[StringLength(25, ErrorMessage = "Must be under 25 characters")]
[Display(Name="Model Number")]
public string ModelNumber { get; set; }
//related objects and necesary properties
public virtual Warranty Warranty { get; set; }
public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; }
主计长(职位)(在建工程):
视图(简化):
@标签(“保修”,新的{@class=“控制标签col-md-2”})
@Html.DropDownListFor(x=>x.Warranty.WarrantyId,Model.Warranty选择列表项,“--Select-->”)
@Html.ValidationMessageFor(model=>model.Warranty.WarrantyId)
同样,我只想知道设置这些viewmodels和models的正确/最佳方法,以便EF尽可能多地完成工作我觉得如果我必须创建一个保修ID
字段,我是做错了什么,但可能不是这样。
提前谢谢。非常感谢您提供的任何见解/帮助。您的视图模型中必须有int-WarrantyId。 比你认为的要好
@Html.DropDownListFor(x => x.WarrantyId, Model.WarrantySelectListItems, "--Select--")
在控制器(POST)中,获取保修ID(从下拉列表中选择)并从数据库中查找对象(var保修=db.warranty.Where(w=>w.WarrantyId==editModel.WarrantyId或类似的内容),然后将该对象分配给modelEntity。视图模型中必须有int-WarrantyId。 比你认为的要好
@Html.DropDownListFor(x => x.WarrantyId, Model.WarrantySelectListItems, "--Select--")
在控制器(POST)中,获取保修ID(从下拉列表中选择)并从数据库中查找对象(var保修=db.warranty.Where(w=>w.WarrantyId==editModel.WarrantyId或类似的内容),然后将该对象分配给modelEntity。您处理的肯定是导航属性(模型类上的虚拟属性),这很好地解释了它们: 定义这些的难点在于如何为数据库设置DbContext。官方文档如下: 简单的父子关系非常容易处理,还有一些情况(更复杂),您可以定义一些物理上来自表中同一行的模型,但我认为您在这里没有处理这些问题 MVC部分是一个独立的关注点,理想情况下您应该这样对待它。控制器代码应该只委托真正的“工作”工作单元模式,如果你选择使用它的话,在你遇到需要跨多个表或实体集持久化/编辑大量内容的情况时才是真正必要的,因为你可能希望它作为一个整体失败或成功。如果你只是在处理单个对象的简单持久化,不要这样做甚至使用工作单元模式使其复杂化
EF或任何ORM框架需要记住的另一件事是,它需要跟踪更改或与现有记录进行比较,因此当您完成此操作时,键值变得非常重要。您处理的肯定是导航属性(模型类上的虚拟属性),这很好地解释了它们: 定义这些的难点在于如何为数据库设置DbContext。官方文档如下: 简单的父子关系非常容易处理,还有一些情况(更复杂),您可以定义一些物理上来自表中同一行的模型,但我认为您在这里没有处理这些问题 MVC部分是一个独立的关注点,理想情况下您应该这样对待它。控制器代码应该只委托真正的“工作”工作单元模式,如果你选择使用它的话,在你遇到需要跨多个表或实体集持久化/编辑大量内容的情况时才是真正必要的,因为你可能希望它作为一个整体失败或成功。如果你只是在处理单个对象的简单持久化,不要这样做甚至使用工作单元模式使其复杂化 EF或任何ORM框架需要记住的另一件事是,它需要跟踪更改或与现有记录进行比较,因此当您完成此项工作时,键值变得非常重要 出于编辑目的,如果我有一个ProductModel模型 保修模型关系,我应该使用虚拟财产吗 视图模型中的保修,还是我应该使用int保修ID 对于
ViewModel
的属性,不能使用virtual
关键字,因为ViewModel
与实体框架无关。
使用virtual
关键字的原因是允许在实体框架中延迟加载
在产品POCO类中的保修导航属性中,您可以访问保修属性,如下所示:
Model.Warranty.WarrantyId
public class Product
{
public int ModelId { get; set; }
public int ModelNumber { get; set; }
public int WarrantyId {get;set;}
[ForeignKey("WarrantyId ")]
public virtual Warranty Warranty { get; set; }
}
它没有将保修信息保存到数据库中的原因是,您需要在产品类中定义保修外键属性
在您的情况下,如果您使用的是代码优先的方法,并且产品是您的POCO类,只需将其保持如下所示:
Model.Warranty.WarrantyId
public class Product
{
public int ModelId { get; set; }
public int ModelNumber { get; set; }
public int WarrantyId {get;set;}
[ForeignKey("WarrantyId ")]
public virtual Warranty Warranty { get; set; }
}
然后,您的ViewModel:
public class MyViewModel
{
public Product Product { get; set; }
public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; }
}
O
@model MyViewModel
@Html.DropDownList("Product.Warranty.WarrantyId", Model.WarrantySelectListItems, "--Select--")
@Html.ValidationMessageFor("Product.Warranty.WarrantyId")
public class ViewAViewModel
{
[Required]
public int WarrantyId { get; set; }
}
public class ViewBViewModel
{
// No longer required.
public int WarrantyId { get; set; }
}
public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; }
public int ModelId { get; set; }
// Removed for clarity, include needed properties in the UI
public int WarrantyId { get; set; }
public IEnumerable<SelectListItem> WarrantySelectListItems { get; set; }
public ActionResult Edit(int? id)
{
//check the id
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
//get the model and make sure the object is populated
var model = _modelService.GetModel(id.Value);
if (model == null)
{
return HttpNotFound();
}
//pass our entity (db) model to our view model
var editViewModel = new EditViewModel();
editViewModel.InjectFrom(model);
// You could instead create a custom injection like FlatLoopValueInjection
// That would flatten and remove duplicates from
// Model.Warranty.WarrantyId to ViewModel.WarrantyId
editViewModel.WarrantyId = model.Warranty.Id;
//warranty select list
editViewModel.WarrantySelectListItems = WarrantySelectList(editViewModel.WarrantyId);
return View(editViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditViewModel editViewModel)
{
if (!ModelState.IsValid)
{
return View(editViewModel);
}
// You need to reconstruct the model itself, there are faster ways but I wanted
// to showcase the logic behind it
// I didn't do any null check or anything to simplify
// Load the model used from the database
var modelEntity = _modelService.GetModel(editViewModel.ModelId);
// You can do an InjectFrom for the other properties you need
// with custom Injection to unflatten
modelEntity.InjectFrom(editViewModel);
// Load the selected warranty from the database
var warrantyEntity = _warrantyService.GetWarranty(editViewModel.WarrantyId);
// Update the warranty of the model with the one loaded
modelEntity.Warranty = warrantyEntity;
_modelService.Update(modelEntity);
_unitOfWork.Save();
return RedirectToAction("Index");
}
<div class="form-group">
@Html.Label("Warranty", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(x => x.WarrantyId, Model.WarrantySelectListItems, "--Select--")
@Html.ValidationMessageFor(model => model.WarrantyId)
</div>
</div>
Model.Warranty.Id => (flatten) => Model.WarrantyId => (unflatten) => Model.Warranty.Id