Adm*_*vić 3 entity-framework ef-code-first asp.net-mvc-3
假设我有一个名为User的类,这是我的基本实体(我将它与DbContext用作DbSet用户),我用作数据访问层的基础级别.让我们说课程看起来像这样:
public class User
{
[Key]
public int Id { get; set; }
public bool Active { get; set; }
public string Description { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public byte[] Photo { get; set; }
public DateTime Created { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在我想要纯视图,我只显示用户是否处于活动状态,以及允许我更改该值的简单复选框.我不想加载任何其他实体属性,特别是属性Photo,因为它只是疯了.我创建了这样的ActivateUserModel:
public class ActivateUserModel
{
[Key]
public int Id { get; set; }
public bool Active { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我有一个名为Activate的强类型视图,它接受ActivateUserModel并显示它(它只是一个复选框并为Id隐藏)然后我有[HttpPost]激活动作捕获ActivateUserModel,将其转换为User实体,然后将更改保存到数据库.这是POST动作:
[HttpPost]
public ActionResult Activate(ActivateUserModel model)
{
if (ModelState.IsValid)
{
User user = new User { Id = model.Id, Active = model.Active };
db.Users.Attach(user);
db.Entry(user).Property(u => u.Active).IsModified = true;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
这就像一个魅力.我已经监视了针对SQL服务器发出的查询,并且我加载的所有内容都是对Id/Active,我更新的所有内容都是基于id的Active更改.
但是我不喜欢它看起来的代码.假设我有50个属性的实体,并且视图有25个.我不想写25行,我说IsModified = true.
所以我的问题是:是否有更有效的方法来做同样的事情,而不是深入研究任何基于反射的方法?我想将数据从任何视图模型传输到实体,然后只保存这些属性.
提前谢谢你的回复,我希望我的问题足够明确:)
你可以这样做:
[HttpPost]
public ActionResult Activate(ActivateUserModel model)
{
if (ModelState.IsValid)
{
User user = db.Users.Single(u => u.Id == model.Id);
db.Entry(user).CurrentValues.SetValues(model);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
db.Entry(user).CurrentValues.SetValues(model)将检查属性是否user也存在同名model,如果是,则将属性值复制model到user.如果不是,它将保持属性值user不变.
我怀疑这不是基于反思的.但上面的代码是直截了当的方式,旨在完全支持您的方案.
编辑
上面的代码加载user包括Photo属性在内的完整实体.如果您不想加载潜在的大二进制字段,我建议使用除IsModified技巧之外的其他策略解决此问题.使用实体框架进行更新强烈依赖于更改跟踪,这需要您加载完整实体.当您尝试避免这种情况并Modified手动设置特定属性的标志时,您将使代码复杂化.
您可能知道,从数据库中获取实体时,不能排除单个标量属性的加载.我建议将Photo属性移动到一个新实体UserPhoto,该实体只有一个Id和Photo属性,并将导航属性UserPhoto放入User类中.然后,如果您想要将照片User与否一起加载,您可以通过延迟,急切或显式加载来决定.
您可以在两者之间创建一对一映射User,UserPhoto如果要将其存储UserPhoto在单独的表中.或者您甚至可以将Photo列留在User表中,User并UserPhoto通过Table Splitting将两个实体映射到同一个表.
编辑2
请参阅您的评论,该方法加载"不必要的东西".我忘了提到以下内容:
实际上,在上面的代码中,您需要从数据库加载实体的成本.但是,当您使用EF 应用于model加载的实体时,只会标记与数据库中的原始值相比真正发生更改的属性.生成的UPDATE语句仅包含这些列.因此,编写UPDATE语句的成本最小化.userSetValues(model)Modified
如果您不想加载实体,则不知道数据库中的当前列值,并且您不知道实际更改了什么.您唯一的机会是强制所有属性的UPDATE 以确保数据库中的行得到正确更新.在您的考试中,您必须为IsModifiedViewModel中包含的所有25个属性设置true.生成的SLQ UPDATE语句将包含所有25列.因此,UPDATE语句可能要贵得多,而且 - 借用你的话 - 不必要的东西.
| 归档时间: |
|
| 查看次数: |
955 次 |
| 最近记录: |