简体   繁体   English

从一对多关系中删除子对象

[英]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 ChildDetailsChildDetails相关的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.DeletedEntityState.Detached然后在我遍历设置它们的视图模型的值时到EntityState.AddedEntityState.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM