簡體   English   中英

在列表AutoMapper和EF6之間移動對象

[英]Moving objects between lists AutoMapper and EF6

我已經開始使用這個擴展了,只想說它的優秀,謝謝!

現在我有一個問題,一個對象可以從一個集合移動到另一個集合,當我這樣做時,我得到一個例外

InvalidOperationException:違反了多重性約束

我猜這是因為該對象沒有在原始集合中找到,並且此擴展將對象添加到新集合中,即使我希望它也被移動,然后在保存時,EF拋出異常,因為我有2對我的上下文使用相同鍵的對象。

但是我怎么能讓它發揮作用呢?

所以如果我有以下對象結構

MyRoot
   | Collection
            | MyChild
                    | Collection
                            | MyObject (1)
            | MyChild
                    | Collection
                            | MyObject (2)

如何將MyObject (1)移動到與MyObject (2)相同的集合中?

這些都是基本對象,這里有一些簡單的代碼

public class MyRoot
{
    public int Id { get; set; }

    public ICollection<MyChild> MyChildren { get; set; }
}

public class MyChild
{
    public int Id { get; set; }

    public int RootId { get; set; }

    public MyRoot Root { get; set; }

    public ICollection<MyObject> MyObjects { get; set; }
}

public class MyObject
{
    public int Id { get; set; }

    public string Name { get; set; }

    public int ChildId { get; set; }

    public MyChild Child { get; set; }
}

這些對象中的每一個都有一個DTO,為了這個例子,我們只是說對象完全相同,最后有擴展DTO(在實際應用中不是這種情況)

在我的應用程序中,我有一個自動化配置文件,就像這樣

internal class MyProfile: Profile
{
    public MyProfile()
    {
        this.CreateMap<MyRoot, MyRootDTO>()
            .ReverseMap();

        this.CreateMap<MyChild, MyChildDTO>()
            .ReverseMap()
            .EqualityComparison((s, d) => s.Id == d.Id);

        this.CreateMap<MyObject, MyObjectDTO>()
            .ReverseMap()
            .EqualityComparison((s, d) => s.Id == d.Id);
    }
}

在我的web api控制器方法上,我有這個,這很簡單

public async Task<IActionResult> UpdateAsync([FromBody] MyRootDTO model)
{
    // get the object and all children, using EF6
    var entity = await _service.GetAsync(model.Id);

    // map
    _mapper.Map(model, entity);

    // pass object now updated with DTO changes to save
    await _service.UpdateAsync(entity);

    // return
    return new OkObjectResult(_mapper.Map<MyRootDTO>(entity));
}

如果有人可以請求幫助,那就太好了!

我不認為你的問題與AutoMapper有任何關系,這是一個實體框架問題。 如果從EF中的子集合中刪除某些內容,除非您在其上調用.Delete,或者該對象的鍵是包含父項的復合鍵,否則它不會自動刪除。

我建議制作一個復合鍵,如下所示:

public class MyObject
{
    [Column(Order = 1)]
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    [Column(Order = 0)]
    [Key]
    public int ChildId { get; set; }

    public MyChild Child { get; set; }
}

[DatabaseGenerated]選項將Id列保留為Identity - EF的默認值與復合鍵不具有自動標識。

您可以在MyChild實體上執行相同的MyChild

為了使其工作,我沒有更改EF鍵,但在我的AutoMapper配置文件中實現了一個方法。 我遍歷該對象以查看該子項是否在不同的列表中,如果是,則將該對象移動到該新列表中。 這樣,automapper仍然能夠基於ID匹配對象。

我將以下代碼添加到.BeforeMap方法中

在本例中,我的基本級別對象不是名為Root ,因此參數s的類型為RootModel (來自我的web api),參數d的類型為Root (來自EF)。 RootModelRoot都有一個名為Sections的集合

.BeforeMap((s, d) =>
{
    // we are going to check if any child has been moved from 1 parent to another, and
    // if so, move the child before the mapping takes place, this way AutoMapper.Collections will not
    // mark the object as orphaned in the first place!
    foreach (var srcParent in s.Sections)
    {
        // only loop through old measures, so ID will not be zero
        foreach (var srcChild in srcParent.Children.Where(e => e.Id != 0))
        {
            // check if the srcChild is in the same dest parent?
            var destChild = d.Sections.SelectMany(e => e.Children).Where(e => e.Id == srcChild.Id).FirstOrDefault();

            // make sure destination measure exists
            if (destChild != null)
            {
                // does the destination child section id match the source section id? If not, child has been moved
                if (destChild.ParentId != srcParent.Id)
                {
                    // now we need to move the child into the new parent, so lets find the destination
                    // parent that the child should be moved into
                    var oldParent = destChild.Parent;
                    var newParent = d.Sections.Where(e => e.Id == srcParent.Id).FirstOrDefault();

                    // remove child from children collection on oldSection and add to newSection
                    oldParent.Children.Remove(destChild);

                    // if newParent is NULL, it is because this is a NEW section, so we need to add this new section
                    // NOTE: Root is my based level object, so your will be different
                    if (newParent == null)
                    {
                        newParent = new Parent();
                        d.Sections.Add(newParent);
                        newParent.Root = d;
                        newParent.RootId = d.Id;
                    }
                    else
                    {
                        // change references on the child
                        destChild.Parent = newParent;
                        destChild.ParentId = newParent.Id;
                    }

                    newParent.Children.Add(destChild);
                }
            }
        }
    }
})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM