在列表AutoMapper和EF6之间移动对象

时间:2017-06-27 16:09:12

标签: c# .net entity-framework entity-framework-6 automapper

我已经开始使用this扩展程序,只想说它非常好,谢谢!

现在我有一个问题,一个对象可以从一个集合移动到另一个集合,当我这样做时,我得到一个异常

  

InvalidOperationException:违反了多重性约束

我猜这是因为该对象未在原始集合中找到,并且此扩展将对象添加到新集合中,即使我希望它也被移动,然后在保存时,EF抛出异常,因为我有两个对象与我的上下文相同的键。

但是我怎么能让它发挥作用呢?

所以,如果我有以下对象结构

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));
}

如果有人可以请求帮助,那就太棒了!

2 个答案:

答案 0 :(得分:0)

我不认为你的问题与AutoMapper有任何关系,这是一个实体框架问题。如果从EF中的子集合中删除某些内容,除非您在其上调用.Delete,或者该对象的键是包含父项的复合键,否则它不会自动删除。

我建议制作一个复合键,例如:

const collection = 'books';
db[collection].find()

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]列保留为标识 - EF的默认值与复合键不具有自动标识。

您可以在Id实体上执行相同的操作。

答案 1 :(得分:0)

为了使其工作,我没有更改EF键,但在我的AutoMapper配置文件中实现了一个方法。我遍历该对象以查看该子项是否在不同的列表中,如果是,则将该对象移动到该新列表中。这样,automapper就能够基于ID来匹配对象。

我将以下代码添加到.BeforeMap方法

在此示例中,不是我的基础对象被称为Root,因此参数s的类型为RootModel(来自我的网络API),参数d的类型为{ {1}}(来自EF)。 RootRootModel都有一个名为Root

的集合
Sections