我正在使用ASP.NET MVC 5和Entity Framework 6.我有一个页面,允许用户输入流程信息。此信息的一个方面是从 Starting Process 的下拉菜单中进行选择。这个类大致如下:
**
public class SupportProcess
{
[Key]
public int ProcessId { get; set; }
[DisplayName("Starting process?")]
public virtual SupportProcess StartProcess { get; set; }
public string Name { get; set; }
[DisplayName("When is this run?")]
public virtual ProcessSchedule ProcessSchedule { get; set; }
[DisplayName("")]
public string Description { get; set; }
[DisplayName("Expected Result")]
public string ExpectedResult { get; set; }
}
**
我使用的视图模型具有SupportProcess的属性,选定的启动过程以及用于填充视图下拉列表的进程列表。
public class SupportProcessViewModel
{
public SupportProcess SupportProcess { get; set; }
public int SelectedStartProcess { get; set; }
public List<SupportProcess> Processes { get; set; }
public SupportProcessViewModel()
{
this.SupportProcess = new SupportProcess();
}
}
我的编辑帖子操作如下:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SupportProcessViewModel vm)
{
if (ModelState.IsValid)
{
if (vm.SelectedStartProcess > 0)
{
vm.SupportProcess.StartProcess = db.SupportProcesses.Find(vm.SelectedStartProcess);
}
db.Entry(vm.SupportProcess).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
问题是,虽然 vm.SelectedStartProcess 不是null并且具有正确的值,但它永远不会保存到数据库中。数据库将此字段显示为 StartProcess_ProcessId 。另外值得注意的是,一个进程可能有0或1个启动进程。
我想知道EF是否在数据库表中为此属性设置了一个外键,实际上它指向同一个表,这在某种程度上导致了这个问题。我全神贯注地寻求建议。
我还要添加“创建发布”操作按预期工作。这必须与传达给EF的事实有关,即StartProcess属性也需要在实体上更新。但这是一个猜测...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create( SupportProcessViewModel vm)
{
if (ModelState.IsValid)
{
if(vm.SelectedStartProcess > 0) {
vm.SupportProcess.StartProcess = db.SupportProcesses.Find(vm.SelectedStartProcess);
}
db.SupportProcesses.Add(vm.SupportProcess);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
答案 0 :(得分:8)
没有显式原始FK属性的引用导航属性的问题是,影子FK状态由已从中检索实体的DbContext
维护。在像您这样的断开连接的场景中丢失了哪些信息。
当您调用
时db.Entry(entity).State = EntityState.Modified;
对于已断开连接的实体,EF会将实体附加到上下文,并将所有原始属性标记为已修改。参考导航属性被视为未更改,因此在您调用SaveChanges
时不会更新它们。
要让EF更新FK,了解原始参考属性值和新参考属性值至关重要。在您的情况下,传递的StartProcess
实体的SupportProcess
属性的原始值。
由于在断开连接的场景中(特别是像你这样的延迟加载属性)你不能依赖传递的对象属性值,我建议采用以下安全操作序列:
(1)将导航属性设置为null
,以避免将值附加到上下文中
(2)将实体附加到上下文并将其标记为已修改
(3)显式加载导航属性。这将导致额外的数据库跳闸,但将确保更新正常
(4)设置导航属性的新值。当您致电SaveChanges
时,上下文更改跟踪器将能够确定是否需要FK更新。
将它应用于您的案例:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SupportProcessViewModel vm)
{
if (ModelState.IsValid)
{
// (1)
vm.SupportProcess.StartProcess = null;
// (2)
db.Entry(vm.SupportProcess).State = EntityState.Modified;
// (3)
db.Entry(vm.SupportProcess).Reference(e => e.StartProcess).Load();
// (4)
vm.SupportProcess.StartProcess =
vm.SelectedStartProcess > 0 ?
db.SupportProcesses.Find(vm.SelectedStartProcess) :
null;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
答案 1 :(得分:0)
我认为你的Edit ActionResult
应该看起来像这样
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SupportProcessViewModel vm)
{
if (ModelState.IsValid)
{
if (vm.SelectedStartProcess > 0)
{
vm.SupportProcess.StartProcess = db.SupportProcesses.Find(vm.SelectedStartProcess);
}
db.SupportProcess.Attach(vm.SupportProcess);
db.Entry(vm.SupportProcess).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
答案 2 :(得分:0)
确保您的模型配置正确:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.icafe4j.image.meta.Metadata;
import com.icafe4j.image.meta.exif.Exif;
import com.icafe4j.image.meta.jpeg.JpegExif;
import com.icafe4j.image.meta.exif.ExifTag;
import com.icafe4j.image.tiff.TiffTag;
import com.icafe4j.image.tiff.FieldType;
public class TestWindowsXP {
public static void main(String[] args) throws IOException {
FileInputStream fin = new FileInputStream(Fm_filePathIn);
FileOutputStream fout = new FileOutputStream(Fm_filePathOut);
List<Metadata> metaList = new ArrayList<Metadata>();
Exif exif = new JpegExif();
exif.addImageField(TiffTag.WINDOWS_XP_AUTHOR, FieldType.WINDOWSXP, "Toto");
exif.addImageField(TiffTag.WINDOWS_XP_KEYWORDS, FieldType.WINDOWSXP, "Copyright;Authorbisou");
// Insert ThumbNailIFD
// Since we don't provide thumbnail image, it will be created later from the input stream
exif.setThumbnailRequired(true);
metaList.add(exif);
Metadata.insertMetadata(metaList, fin, fout);
fin.close();
fout.close();
}
}
你的编辑方法:
public class SupportProcess
{
[Key]
public int ProcessId { get; set; }
[DisplayName("Starting process?")]
public int StartProcessId { get; set; }
[ForeignKey("StartProcessId")]
public virtual SupportProcess StartProcess { get; set; }
public string Name { get; set; }
[DisplayName("When is this run?")]
public virtual ProcessSchedule ProcessSchedule { get; set; }
[DisplayName("")]
public string Description { get; set; }
[DisplayName("Expected Result")]
public string ExpectedResult { get; set; }
}