问题描述
我一直在关注Apress Pro ASP.NET MVC 3 Framework书中的Sportsstore示例项目,并尝试将这些概念应用于我的应用程序。困扰我的一个方面是,在示例中,我可以将图像添加到产品中并将其保存到数据库中,但是如果我编辑任何给定的产品而没有为其上传新图像,则图像数据将被清除。 。我希望能够编辑产品,但是如果HTTP帖子返回的图像数据为null,则我希望Entity Framework保留现有的图像数据(和内容类型)。如果未上传新图像,我该如何命令EF不要将此图像字段更新为null?
[HttpPost]
public ActionResult Edit(int id,HttpPostedFileBase image1,FormCollection collection)
{
using (ISession session = Database.OpenSession())
{
try
{
DoctorsModel db = new DoctorsModel();
db.Id_d = id;
db.D_city = collection["D_city"].ToString();
db.D_egn = collection["D_egn"].ToString();
db.D_email = collection["D_email"].ToString();
db.D_family_name = collection["D_family_name"].ToString();
db.D_first_name = collection["D_first_name"].ToString();
db.D_gender = collection["D_gender"].ToString();
db.D_mid_name = collection["D_mid_name"].ToString();
db.D_phone = collection["D_phone"].ToString();
db.D_specialty = collection["D_specialty"].ToString();
db.D_room = collection["D_room"].ToString();
db.D_floor = collection["D_floor"].ToString();
if (image1 != null)
{
db.D_picture = new byte[image1.ContentLength];
image1.InputStream.Read(db.D_picture,image1.ContentLength);
}
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(db);
transaction.Commit();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
型号
public class DoctorsModel
{
public virtual int Id_d { get; set; }
[display (Name ="Име: ")]
public virtual string D_first_name { get; set; }
[display(Name = "Презиме: ")]
public virtual string D_mid_name { get; set; }
[display(Name = "Фамилия: ")]
public virtual string D_family_name { get; set; }
[display(Name = "Специалност: ")]
public virtual string D_specialty { get; set; }
[display(Name = "Пол: ")]
public virtual string D_gender { get; set; }
[display(Name = "Тел.номер: ")]
public virtual string D_phone { get; set; }
[display(Name = "Email: ")]
public virtual string D_email { get; set; }
[display(Name = "ЕГН: ")]
public virtual string D_egn { get; set; }
[display(Name = "Град: ")]
public virtual string D_city { get; set; }
[display(Name = "Снимка: ")]
public virtual byte[] D_picture { get; set; }
[StringLength(5)]
public virtual string D_rating { get; set; }
public virtual string D_content { get; set; }
[display(Name = "Стая:" )]
public virtual string D_room { get; set; }
[display(Name = "Етаж: ")]
public virtual string D_floor { get; set; }
}
解决方法
如果要解决用于迁移和初始数据填充方案的EF AddOrUpdate
,或者精简到DbContext.Update(doctor),则问题将尝试使用“ SaveOrUpdate”之类的东西然后您的数据将被#null覆盖。您为EF提供了一个实体,可以在不考虑已有数据的情况下进行插入或更新。 EF只会根据提供的实体中所填充的所有字段进行“存在”检查,然后发出INSERT或有效地执行UPDATE *。
对于RESTful API,应该分别通过发出POST
或PUT
来区分“添加”和“更新”。在POST上,获取数据,创建一个新模型,将其添加到DB Context和SaveChanges
中。对于PUT
,您获取当前模型,更新适当的值,然后SaveChanges
。如果找不到PUT
操作,则永远不要插入该行。
您的方法似乎仅用于更新现有记录:
[HttpPut]
public ActionResult Edit(int id,HttpPostedFileBase image1,FormCollection collection)
{
using (var context = new AppDbContext())
{
try
{
var doctor = context.Doctors.Single(x => x.Id == id); // Will throw if Dr not found.
doctor.D_city = collection["D_city"].ToString();
doctor.D_egn = collection["D_egn"].ToString();
doctor.D_email = collection["D_email"].ToString();
doctor.D_family_name = collection["D_family_name"].ToString();
doctor.D_first_name = collection["D_first_name"].ToString();
doctor.D_gender = collection["D_gender"].ToString();
doctor.D_mid_name = collection["D_mid_name"].ToString();
doctor.D_phone = collection["D_phone"].ToString();
doctor.D_specialty = collection["D_specialty"].ToString();
doctor.D_room = collection["D_room"].ToString();
doctor.D_floor = collection["D_floor"].ToString();
if (image1 != null)
{
doctor.D_picture = new byte[image1.ContentLength];
image1.InputStream.Read(doctor.D_picture,image1.ContentLength);
}
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{ // do more than this. :)
return View();
}
}
}
理想情况下,将注入DbContext或UnitOfWork。很难知道您的Session实现会执行什么操作或与DbContext进行交互。我通常不建议尝试抽象EF DbContext,因为它确实削弱了它提供的有效使用数据实体的功能。对于更新操作,请获取现有实体,然后在其中复制值。默认情况下,DbContext使用跟踪的实体,因此当您实际更改值时,这些实体将包含在UPDATE语句中。任何未明确更改的内容将保持原样,并且不会添加到UPDATE查询中。
对于像“图像”这样不经常使用的潜在大数据,我建议考虑将其隔离到相关的表/实体中。即
public class DoctorImage
{
[Key]
public int Id { get; set; } // == Doctor.Id
public byte[] Image { get; set; }
}
其中Doctor与DoctorImage的关系设置为HasOptional.WithRequired / HasOne.WithOne。好处是,在与Doctors交往时加载图像是完全可选的。除非您在所有地方都明确使用投影,否则加载现有Doctor实体将导致EF每次可能不需要时都获取Image。通过分离它,您仅在显式渴望/延迟加载时才获取它。例如,列出医生可以轻松完成,而无需加载所有图像数据的开销。