实体框架+ AutoMapper(实体到DTO和DTO到实体)

时间:2009-05-21 09:03:54

标签: c# entity-framework automapper dto

我在使用EF和AutoMapper时遇到了一些问题。 = /

例如:

我有2个相关实体(客户和订单) 他们是DTO课程:  


class CustomerDTO
{
   public string CustomerID {get;set;}
   public string CustomerName {get;set;}
   public IList< OrderDTO > Orders {get;set;}
}

class OrderDTO { public string OrderID {get;set;} public string OrderDetails {get;set;} public CustomerDTO Customers {get;set;} }

//when mapping Entity to DTO the code works Customers cust = getCustomer(id); Mapper.CreateMap< Customers, CustomerDTO >(); Mapper.CreateMap< Orders, OrderDTO >(); CustomerDTO custDTO = Mapper.Map(cust);

//but when i try to map back from DTO to Entity it fails with AutoMapperMappingException. Mapper.Reset(); Mapper.CreateMap< CustomerDTO , Customers >(); Mapper.CreateMap< OrderDTO , Orders >(); Customers customerModel = Mapper.Map< CustomerDTO ,Customers >(custDTO); // exception is thrown here

我做错了吗?

提前致谢!

8 个答案:

答案 0 :(得分:18)

我遇到的问题与EntityCollection引用的更新有关。当从DTO映射到实体时,AutoMapper会创建关系的新实例,而不会取悦EF。

解决了我的问题是配置AutoMapper以使用我的EntityCollection属性的目标值。在你的情况下:

Mapper.CreateMap< CustomerDTO , Customers >().ForMember(c => c.Orders, o => o.UseDestinationValue());

这样AM就不会创建新的EntityCollection实例,并且将使用原始Customer实体附带的实例。

我仍然在努力实现自动化,但是现在它解决了我的问题。

答案 1 :(得分:5)

您的问题是因为Automapper丢失了与记录关联的EntityKey。由于EntityFramework默认情况下不处理POCO(普通旧CLR对象)

Jay Zimmerman在这里有一个很好的例子,说明如何处理这个问题。 gd / 4NIcj 同样来自Jaroslaw Kowalski(EF团队的一部分,我相信)有一个在EF中使用POCO的例子,可以很好地转换为与Automapper一起使用(我还没有机会尝试):http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx < / p>

答案 2 :(得分:4)

我不确定你的问题是什么,但是 - 当我想使用LINQToEntities(切换到NHibernate)时, 我成功地使用了automapper。

看看代码:

public class SimpleMapper<TFrom, TTo>
{
    public static TTo Map(TFrom fromModel)
    {
        Mapper.CreateMap<TFrom, TTo>();
        return Mapper.Map<TFrom, TTo>(fromModel);
    }

    public static IList<TTo> MapList(IList<TFrom> fromModel)
    {
        Mapper.CreateMap<TFrom, TTo>();
        return Mapper.Map<IList<TFrom>, IList<TTo>>(fromModel);
    }
}

public class RepositoryBase<TModel, TLINQModel>
{
    public IList<TModel> Map<TCustom>(IList<TCustom> model)
    {
        return SimpleMapper<TCustom, TModel>.MapList(model);
    }

    public TModel Map(TLINQModel model)
    {
        return SimpleMapper<TLINQModel, TModel>.Map(model);
    }

    public TLINQModel Map(TModel model)
    {
        return SimpleMapper<TModel, TLINQModel>.Map(model);
    }

    public IList<TModel> Map(IList<TLINQModel> model)
    {
        return SimpleMapper<TLINQModel, TModel>.MapList(model);
    }

    public IList<TLINQModel> Map(IList<TModel> model)
    {
        return SimpleMapper<TModel, TLINQModel>.MapList(model);
    }
}

它非常神秘,总是重新创建映射,但它确实有效。我希望它有所帮助。 :)

答案 3 :(得分:4)

尝试映射到现有对象:

entity = Mapper.Map<MyDTO, NyEntity>(dto, entity); 

并将Ignore()保持在原位。

http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1

答案 4 :(得分:3)

现在,使用新版本的AutoMapper,推荐的方法是使用Queryable-Extensions

  

使用NHM或ORMP框架等ORM时   AutoMapper的标准Mapper.Map函数,你可能会注意到   ORM将在图表中查询所有对象的所有字段   AutoMapper正在尝试将结果映射到目标类型。

     

如果你的ORM暴露了IQueryables,你可以使用AutoMapper   QueryableExtensions帮助方法来解决这个关键的痛苦。

     

.ProjectTo()将告诉AutoMapper的映射引擎   向IQueryable发出一个select子句,它将通知实体   它只需要查询Item的Name列的框架   表,就像手动将IQueryable手动投影到一样   带有Select子句的OrderLineDTO。

创建映射:

var customerDto = 
   session.Query<Customer>().Where(customer => customer.Id == id)
   .Project().To<CustomerDto>()
   .Single();

将项目查询到dto:

{{1}}

答案 5 :(得分:2)

AutoMapper在映射错误方面非常具有表现力。仔细阅读异常消息。

另一个重要的事情是要记住调用Mapper.AssertConfigurationIsValid();创建映射后。如果映射错误,则会出错,从而在应用程序运行时稍后阻止异常。

答案 6 :(得分:2)

您应该忽略某些实体属性的映射,如下所示:

Mapper.CreateMap<CustomerDto, Customer>()
                .ForMember(dest => dest.EntityKey, opt => opt.Ignore())
                .ForMember(dest => dest.Licenses, opt => opt.Ignore())
                .ForMember(dest => dest.AccessCodes, opt => opt.Ignore());

如果检查来自Automapper抛出的异常的消息,您应该看到无法映射的实体属性,并忽略它们。

答案 7 :(得分:0)

正如您可以阅读here,您需要执行以下操作

您可以使用AutoMapper更新实体。方法如下:将DTO和实体对象都传递给AutoMapper的Map方法。这就是这段代码的作用:

custExisting = Mapper.Map(Of CustomerDTO,  Customer)(custDTO, custExisting)

还要注意映射问题,如here

所述

这些提示对我有用。