[英]Delete child object from One-To-Many Relationship
(Code has been simplified) (代码已简化)
Background description: 背景说明:
I have a parent class: 我有一个家长班:
namespace Project_Name.Models
{
public class ParentRecord
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual ICollection<ChildDetail> ChildDetails { get; set; }
}
}
and a child class: 和一个孩子班:
namespace Project_Name.Models
{
public class ChildDetail
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Value { get; set; }
public Guid ParentRecord_Id { get; set; }
[ForeignKey("ParentRecord_Id")]
public ParentRecord ParentRecord { get; set; }
}
}
I also have ViewModels with the names <modelName>ViewModel
and almost exact structure, except with no Data Annotations and virtual ICollection
is just a List
我也有名称为<modelName>ViewModel
和几乎精确的结构,除了没有数据注释和virtual ICollection
只是一个List
Together they form a One-to-Many relationship. 他们一起形成一对多的关系。 ParentRecord
can have many ChildDetails
, and ChildDetail
must be associated with a ParentRecord
. ParentRecord
可以有很多ChildDetails
,并ChildDetail
必须与相关ParentRecord
。
The T-SQL table structure comes out like this: T-SQL表结构如下所示:
dbo.ParentRecord
+-----------+
| Id |
+-----------+
| <cr_guid> |
+-----------+
dbo.ChildDetail
+-----------+-----------+-----------------+
| Id | Value | ParentRecord_Id |
+-----------+-----------+-----------------+
| <cd_guid> | Some Text | <cr_guid> |
+-----------+-----------+-----------------+
My problem: 我的问题:
I need to be able to update, add, and/or remove these child objects based on what my ViewModel has. 我需要能够根据我的ViewModel拥有的内容来更新,添加和/或删除这些子对象。 Whatever it has, I want to be the end result. 不管它有什么,我都想成为最终结果。
For example, I start off by having 3 ChildDetails
related to the ParentRecord
, then in my View I update the 1st ChildDetail
, remove the 2nd (or leave the value blank), and leave the 3rd one alone. 例如,我首先有3 ChildDetails
与ChildDetails
相关的ParentRecord
,然后在我的视图中更新第一个ChildDetail
,删除第二个(或将值保留为空白),第三个单独保留。
I hope my end result to be that this ParentRecord
is left with two ChildDetails
, the 1st and 3rd, with the 1st one being updated. 我希望我的最终结果是,此ParentRecord
剩下两个ChildDetails
,第一个和第三个,第一个被更新。
What I've done so far: 到目前为止,我所做的是:
I'm able to add and update ChildDetails
doing this, but it doesn't handle any deletion: 我可以执行此操作来添加和更新ChildDetails
,但它不能处理任何删除操作:
// ... code related to UnrelatedGranParent model
ParentRecord parentRecord = context.ParentRecords.FirstOrDefault(x =>
x.Id == UnrelatedGrandParentViewModel.ParentViewModel.Id)
// ... code regarding ParentRecord's other not-shown-here properties
// Add or update each Child Detail from the View Model
foreach (var childDetailViewModel in ParentRecordViewModel
.ChildDetailViewModels
.Where(x => !x.Value.IsNullOrWhiteSpace()))
{
// Map the Child Detail View Model to a Model
var childDetail =
Mapper.Map<ChildDetail>(childDetailViewModel);
// Set the ParentRecord_Id property, since that doesn't get mapped
childDetail.ParentRecord_Id = parentRecord.Id;
// Add or update each Child Detail
context.ChildDetails.AddOrUpdate(childDetail);
}
context.ParentRecord.AddOrUpdate(parentRecord);
context.SaveChanges();
So I want parentRecord.ChildDetails
set to whatever just got passed in, assuming it's not null or whitespace. 所以我想将parentRecord.ChildDetails
设置为刚传入的任何东西,假设它不是null或空格。
So I have to delete everything else. 所以我必须删除其他所有内容。
I've tried looping through each existing ChildDetail
and using either .Remove()
on them or setting their context.Entry(childDetail).State = EntityState.Deleted
or EntityState.Detached
then as I loop through the values from the view model setting them to either EntityState.Added
or EntityState.Modified
, but keeps throwing errors either when I'm changing the state or saving changes depending. 我尝试遍历每个现有的ChildDetail
并在它们上使用ChildDetail
.Remove()
或设置它们的context.Entry(childDetail).State = EntityState.Deleted
或EntityState.Detached
然后在我遍历设置它们的视图模型的值时到EntityState.Added
或EntityState.Modified
,但是当我更改状态或保存更改时,始终抛出错误。
I can also move the .Where(x => !x.Value.IsNullOrWhiteSpace())
into the foreach loop to be: 我还可以将.Where(x => !x.Value.IsNullOrWhiteSpace())
移至foreach循环中,使其成为:
// map the childDetail
if (childDetail.Value.IsNullOrWhiteSpace())
{
context.Entry(childDetail).State = EntityState.Deleted;
continue;
}
context.ChildDetails.AddOrUpdate(childDetail);
But this doesn't account for those simply not passed in, and I don't know if it's a good practice to directly set EntityStates. 但这不能解决那些根本没有传入的问题,而且我不知道直接设置EntityStates是否是一个好习惯。
Thanks to DevilSuichiro's comment I was able to come to this easy solution where I simply check if each ChildDetail
from the context exists in the ViewModel's list of ChildDetails
, and if it doesn't: delete it! 感谢DevilSuichiro的评论,我得以找到一个简单的解决方案,在该解决方案中,我只需检查上下文中的每个ChildDetail
是否存在于ViewModel的ChildDetails
列表中,如果不存在,请删除它!
// Add or update each Child Detail from the View Model
foreach (var childDetailViewModel in callDetailsViewModel.ParentRecordViewModel
.ChildDetailViewModels)
{
// Map the Child Detail View Model to a Model
var childDetail =
Mapper.Map<ChildDetail>(childDetailViewModel);
// Set the ParentRecord_Id property, since that doesn't get mapped
childDetail.ParentRecord_Id = parentRecord.Id;
// Delete those that are null or whitespace
if (childDetail.Value.IsNullOrWhiteSpace())
{
context.Entry(childDetail).State = EntityState.Deleted;
continue;
}
// Add or update each Child Detail
context.ChildDetails.AddOrUpdate(childDetail);
}
// For each contextChildDetail in the context, where they have matching Parent Record Id...
foreach (var contextChildDetail in context.ChildDetail.Where(x => x.ParentRecord_Id == parentRecord.Id))
{
// ... and if we can't find it in the ViewModel list, then delete it
if (callDetailsViewModel.ParentRecordViewModel.ChildDetailViewModels.FirstOrDefault(
x => x.Id == contextChildDetail.Id) == null)
{
context.ChildDetail.Remove(contextChildDetail);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.