在列表中移动对象和EF6



我已经开始使用此扩展名,只是想说它很棒,谢谢!

现在我有一个问题,可以将一个对象从1个集合移动到另一个集合,当我这样做时,我会得到一个例外

无效的exception:违反了多重性约束

我猜这是因为在原始集合中找不到对象,并且该扩展名将对象添加到新集合中,即使我也希望它也被移动,然后保存后,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(在真实应用中不是这种情况(

(

在我的应用程序中,我有一个自动配置文件,例如So

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列作为身份保存 - EF的默认值为复合键,无自动身份。

您可以在MyChild实体上做同样的事情。

为了使其工作,我没有更改EF键,而是在我的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);
                }
            }
        }
    }
})

最新更新