asp.net-mvc – 在Entity Framework中干净地更新层次结构

前端之家收集整理的这篇文章主要介绍了asp.net-mvc – 在Entity Framework中干净地更新层次结构前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在为StoredProcedureReport提交一个表单,该表单有许多StoredProcedureParameters.创建工作正常,但尝试更新让我不知道微软是否可以认真对待.

我来自一个Rails背景,其中@ report.update_attributes(params [:report])将确切知道如何处理它在其中找到的任何关联数据.据我所知,.NET的等价物是TryUpdateModel,看起来很有前景.首先.所以我尝试了这样的一些参数

  1. IDGUID:d70008a5-a1a3-03d2-7baa-e39c5044ad41
  2. StoredProcedureName:GetUsers
  3. Name:search again UPDATED
  4. StoredProcedureReportParameters[0].IDGUID:d70008a5-aba3-7560-a6ef-30a5524fac72
  5. StoredProcedureReportParameters[0].StoredProcedureReportID:d70008a5-a1a3-03d2-7baa-e39c5044ad41
  6. StoredProcedureReportParameters[0].Name:RowsPerPage
  7. StoredProcedureReportParameters[0].Label:rows
  8. StoredProcedureReportParameters[0].StoredProcedureReportParameterDataTypeID:a50008a5-2755-54c0-b052-865abf459f7f
  9. StoredProcedureReportParameters[0].StoredProcedureReportParameterInputTypeID:a50008a5-2955-a593-d00f-00cd4543babf
  10. StoredProcedureReportParameters[0].DefaultValue:10
  11. StoredProcedureReportParameters[0].AllowMultiple:false
  12. StoredProcedureReportParameters[0].Hidden:false
  13. StoredProcedureReportParameters[1].IDGUID:d70008a5-a7a3-e35e-28b6-36dd9e448ee5
  14. StoredProcedureReportParameters[1].StoredProcedureReportID:d70008a5-a1a3-03d2-7baa-e39c5044ad41
  15. StoredProcedureReportParameters[1].Name:PageNumber
  16. StoredProcedureReportParameters[1].Label:page was MODIFIEIIEIEIED!!!
  17. StoredProcedureReportParameters[1].StoredProcedureReportParameterDataTypeID:a50008a5-2755-54c0-b052-865abf459f7f
  18. StoredProcedureReportParameters[1].StoredProcedureReportParameterInputTypeID:a50008a5-2955-a593-d00f-00cd4543babf
  19. StoredProcedureReportParameters[1].DefaultValue:1
  20. StoredProcedureReportParameters[1].AllowMultiple:false
  21. StoredProcedureReportParameters[1].Hidden:false

我假设在设置了所有主键和外键后,EF会知道在执行此操作时如何更新StoredProcedureReportParameter对象:

  1. var report = context.StoredProcedureReports.FirstOrDefault(r => r.IDGUID == reportID);
  2.  
  3. if (report != null)
  4. {
  5. succeeded = TryUpdateModel(report);
  6. context.SaveChanges();
  7. }

现在,如果我在context.SaveChanges()上放置断点,我的报表对象及其关联的StoredProcedureReportParameters看起来就像我期望的那样.设置外键和主键,检查所有值.但SaveChanges引发了这个错误

The operation Failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship,the related foreign-key property is set to a null value. If the foreign-key does not support null values,a new relationship must be defined,the foreign-key property must be assigned another non-null value,or the unrelated object must be deleted.

此消息中的一个建议是我应该为外键属性分配一个非空值,但正如我所说,StoredProcedureReportID在两个StoredProcedureReportParameter对象上都有正确的值.

我读过的其他帖子处理Update操作循环关联并将它们附加到上下文.这真的是我坚持做的吗? EF真的那么密集吗?我希望.NET专家能够向我展示这一点.必须有一种比这更简单的方法.

解决方法

这并不难.使用EF有两种主要的工作方式:附加实体和分离实体.

我们假设我们有2个参与者:

  1. public class Foo
  2. {
  3. public int FooId { get; set; }
  4.  
  5. public string Description { get; set; }
  6.  
  7. public ICollection<Bar> Bars { get; set; }
  8. }
  9.  
  10. public class Bar
  11. {
  12. public int BarId { get; set; }
  13.  
  14. public string Description { get; set; }
  15. }

INSERTING

  1. var foo = new Foo()
  2. {
  3. FooId = 1,Description = "as",Bars = new List<Bar>()
  4. {
  5. new Bar
  6. {
  7. BarId = 1,Description = "as"
  8. },new Bar
  9. {
  10. BarId = 2,Description = "as"
  11. }
  12. }
  13. };
  14.  
  15. ctx.Foos.Add(foo);
  16. ctx.SaveChanges();

在上面的示例中,EF将识别新项目,并将插入所有项目.

更新(附件)

  1. var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault();
  2. foreach (var bar in foo.Bars)
  3. {
  4. bar.Description = "changed";
  5. }
  6.  
  7. ctx.SaveChanges();

这里我们从上下文中加载了foo及其条形图.它们已经附在上下文中.因此,我们需要做的就是更改值并调用SaveChanges().一切都会好起来的.

更新(已分离)

  1. var foo = new Foo
  2. {
  3. FooId = 1,Description = "changed3",Bars = new List<Bar>
  4. {
  5. new Bar
  6. {
  7. BarId = 1,Description = "changed3"
  8. },Description = "changed3"
  9. }
  10. }
  11. };
  12.  
  13. ctx.Entry(foo).State = EntityState.Modified;
  14.  
  15. foreach (var bar in foo.Bars)
  16. {
  17. ctx.Entry(bar).State = EntityState.Modified;
  18. }
  19.  
  20. ctx.SaveChanges();

在这里,我们正在处理数据库中已存在的项目.但是,他们没有从EF加载(他们没有附加). EF对他们一无所知.我们需要手动附加所有这些并告诉EF它们已被修改.

删除(附加)

  1. var foo = ctx.Foos.Include("Bars").Where(i => i.FooId == 1).FirstOrDefault();
  2. var bar = foo.Bars.First();
  3. foo.Bars.Remove(bar);
  4. ctx.SaveChanges();

从EF加载条,然后从集合中删除它们.

删除(已分离)

  1. var bar = new Bar
  2. {
  3. BarId = 1
  4. };
  5.  
  6. ctx.Entry(bar).State = EntityState.Deleted;
  7. ctx.SaveChanges();

这里,Bar没有从上下文中加载.所以,我们必须告诉EF它被删除了.

在您的情况下,您将更新的对象发送到MVC控制器;所以,你必须告诉EF StoredProcedureReport和StoredProcedureParameters被修改.

如果正在修改所有属性,您可以使用:

  1. ctx.Entry(foo).State = EntityState.Modified;
  2. //remember to do the same in all children objects

它会将所有属性标记为已修改.请注意,如果未在视图上设置某些属性,则会将其更新为空值.

如果未修改所有属性,则必须指定属性.喜欢这个:

  1. context.Entry(foo).Property("Description").IsModified = true;
  2. context.Entry(foo).Property("AnotherProperty").IsModified = true;

希望能帮助到你!

猜你在找的asp.Net相关文章