C# 实体框架 + AutoMapper(实体到 DTO 和 DTO 到实体)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/891999/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework + AutoMapper ( Entity to DTO and DTO to Entity )
提问by shkipper
I've got some problems using EF with AutoMapper. =/
我在使用 EF 和 AutoMapper 时遇到了一些问题。=/
for example :
例如 :
I've got 2 related entities ( Customers and Orders ) and they're DTO classes :
我有 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
Am I doing something wrong?
难道我做错了什么?
Thanks in Advance !
提前致谢 !
回答by Arnis Lapsa
I'm not sure what your problem is, but - when i wanted to use LINQToEntities (switched to NHibernate),
i managed to use automapper with success.
我不确定您的问题是什么,但是 - 当我想使用 LINQToEntities(切换到 NHibernate)时,
我成功地使用了 automapper。
Take a look at code:
看一下代码:
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);
}
}
It's quite cryptic, always recreates mappings, but it worked. I hope it helps somehow. :)
它很神秘,总是重新创建映射,但它有效。我希望它以某种方式有所帮助。:)
回答by geva30
AutoMapper is very expressive when it comes to mapping error. read the exception message carefully.
AutoMapper 在映射错误方面非常具有表现力。仔细阅读异常消息。
another important thing is to remember to call Mapper.AssertConfigurationIsValid(); after creating the mappings. it gives an error if the mapping is wrong, thus preventing an exception later in the application runtime.
另一个重要的事情是记住调用 Mapper.AssertConfigurationIsValid(); 创建映射后。如果映射错误,它会给出错误,从而防止应用程序运行时稍后出现异常。
回答by user203510
Your problem is because Automapper loses the EntityKey associated with the record. As the EntityFramework does not by default handle POCO's (Plain Old CLR Object)
您的问题是因为 Automapper 丢失了与记录关联的 EntityKey。由于 EntityFramework 默认不处理 POCO(Plain Old CLR Object)
Jay Zimmerman has a good example here of how to handle this from is. gd /4NIcj Also from Jaroslaw Kowalski (part of the EF team I believe ) has this example for using POCO's within EF, which may translate well to use with Automapper (I've not yet had a chance to try it) : http://blogs.msdn.com/jkowalski/archive/2008/09/09/persistence-ignorance-poco-adapter-for-entity-framework-v1.aspx
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
回答by Pablo Montilla
The problem I had was related to updates to EntityCollection references. AutoMapper creates a new instance of the relation when mapping from the DTO to the Entity, and that doesn't please the EF.
我遇到的问题与 EntityCollection 引用的更新有关。AutoMapper 在从 DTO 映射到实体时创建关系的一个新实例,这让 EF 不满意。
What solved my problem was configuring AutoMapper to use the destination value for my EntityCollection properties. In your case:
解决我的问题的是配置 AutoMapper 以使用我的 EntityCollection 属性的目标值。在你的情况下:
Mapper.CreateMap< CustomerDTO , Customers >().ForMember(c => c.Orders, o => o.UseDestinationValue());
That way AM will not create a new EntityCollection instance, and will use that wich came with the original Customer entity.
这样 AM 不会创建新的 EntityCollection 实例,而是使用原始 Customer 实体附带的那个实例。
I'm still working for a way to automate this, but for now it solves my problem.
我仍在努力寻找一种自动化的方法,但现在它解决了我的问题。
回答by codrin
You should ignore mapping of some entity properties like so:
您应该忽略某些实体属性的映射,如下所示:
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());
If you examine the message from the exception thrown by Automapper, you should see the entity properties that cannot be mapped and ignore them as above.
如果您检查来自 Automapper 抛出的异常的消息,您应该看到无法映射的实体属性,并如上所述忽略它们。
回答by ishakkulekci
Try mapping to an existing object:
尝试映射到现有对象:
entity = Mapper.Map<MyDTO, NyEntity>(dto, entity);
And keep the Ignore()'s in place.
并保持 Ignore() 的位置。
http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1
http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1
回答by Dmytro I.
As you can read hereyou need to do the following
You can update entities with AutoMapper. Here's how: pass both the DTO and the entity object to AutoMapper's Map method. That's what this code does:
您可以使用 AutoMapper 更新实体。方法如下:将 DTO 和实体对象传递给 AutoMapper 的 Map 方法。这就是这段代码的作用:
custExisting = Mapper.Map(Of CustomerDTO, Customer)(custDTO, custExisting)
Also beware of mapping issues like the one described here
还要注意像这里描述的映射问题
These tips worked for me.
这些技巧对我有用。
回答by Dvor_nik
Now, with new version of AutoMapper, the recommended way is using Queryable-Extensions:
现在,有了新版本的 AutoMapper,推荐的方法是使用Queryable-Extensions:
When using an ORM such as NHibernate or Entity Framework with AutoMapper's standard Mapper.Map functions, you may notice that the ORM will query all the fields of all the objectswithin a graph when AutoMapper is attempting to map the results to a destination type.
If your ORM exposes IQueryables, you can use AutoMapper's QueryableExtensions helper methods to address this key pain.
The .ProjectTo() will tell AutoMapper's mapping engine to emit a select clause to the IQueryable that will inform entity framework that it only needs to query the Name column of the Item table, same as if you manually projected your IQueryable to an OrderLineDTO with a Select clause.
当使用带有 AutoMapper 标准 Mapper.Map 函数的 ORM(例如 NHibernate 或实体框架)时,您可能会注意到,当 AutoMapper 尝试将结果映射到目标类型时,ORM 将查询图中所有对象的所有字段。
如果您的 ORM 公开 IQueryables,您可以使用 AutoMapper 的 QueryableExtensions 辅助方法来解决这个关键问题。
.ProjectTo() 将告诉 AutoMapper 的映射引擎向 IQueryable 发出一个 select 子句,该子句将通知实体框架它只需要查询 Item 表的 Name 列,就像您手动将 IQueryable 投影到 OrderLineDTO 一样选择条款。
Create a mapping:
创建映射:
Mapper.CreateMap<Customer, CustomerDto>();
And project query to dto:
以及对 dto 的项目查询:
var customerDto =
session.Query<Customer>().Where(customer => customer.Id == id)
.Project().To<CustomerDto>()
.Single();