.net Automapper:使用 Entity Framework 4 Proxy Pocos 的集合上的继承和抽象基类的映射问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3441916/
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
Automapper : mapping issue with inheritance and abstract base class on collections with Entity Framework 4 Proxy Pocos
提问by Ken Burkhardt
I am having an issue using AutoMapper (which is an excellent technology) to map a business object to a DTO where I have inheritance off of an abstract base class within a collection.
我在使用 AutoMapper(这是一项出色的技术)将业务对象映射到 DTO 时遇到了问题,我在该 DTO 中从集合中的抽象基类继承。
Here are my objects:
这是我的对象:
abstract class Payment
class CashPayment : Payment
class CreditCardPayment : Payment
I also have an invoice object which contains a collection of payments like so:
我还有一个发票对象,其中包含一组付款,如下所示:
public class Invoice
{
... properties...
public ICollection<Payment> Payments { get; set; }
}
I also have corresponding DTO versions of each of these objects.
我还有每个这些对象的相应 DTO 版本。
The DtoInvoice object is defined as:
DtoInvoice 对象定义为:
[DataContract]
public class DtoInvoice
{
...properties...
[DataMember]
public List<DtoPayment> Payments { get; set; }
}
This is what my Mapper definitions look like:
这是我的 Mapper 定义的样子:
Mapper.CreateMap<Invoice, DtoInvoice>();
Mapper.CreateMap<Payment, DtoPayment>()
.Include<CashPayment, DtoCashPayment>()
.Include<CreditCardPayment, DtoCreditCardPayment>();
Mapper.CreateMap<CashPayment, DtoCashPayment>();
Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();
The code to perform the mapping looks like this:
执行映射的代码如下所示:
var invoice = repo.GetInvoice(invoiceId);
var dtoInvoice = Mapper.Map<Invoice, DtoInvoice>(invoice);
So for example if my invoice object contains a collection of specific payments (say 1 cash and 1 credit card) when mapper tries to map them I get an error that the abstract class Payment cannot be created. If I remove the abstract keyword from the Payment object then the code works but I only get a collection of Payment object, I do not get their specific objects (Cash & Credit Card payments).
因此,例如,如果我的发票对象包含一组特定的付款(比如 1 个现金和 1 张信用卡),当映射器尝试映射它们时,我会收到一个错误,提示无法创建抽象类 Payment。如果我从 Payment 对象中删除 abstract 关键字,那么代码可以工作,但我只得到 Payment 对象的集合,我没有得到它们的特定对象(现金和信用卡付款)。
So the question is: How can I get AutoMapper to map the specific payment types and not the base class?
所以问题是:如何让 AutoMapper 映射特定的支付类型而不是基类?
Update
更新
I did some more digging and think I see a problem but am not sure how I can solve this with AutoMapper. I think this is more of an EF thing and not AutoMapper's fault. :-)
我做了更多的挖掘,并认为我看到了一个问题,但我不确定如何使用 AutoMapper 解决这个问题。我认为这更像是 EF 的事情,而不是 AutoMapper 的错。:-)
In my code I am using Entity Framework 4 Proxy POCOs with lazy loading.
在我的代码中,我使用带有延迟加载的 Entity Framework 4 代理 POCO。
So when I try to map an entity returned from EF that is a proxy POCO it gets that funny looking type like:
因此,当我尝试映射从代理 POCO 的 EF 返回的实体时,它会得到类似以下有趣的类型:
System.Data.Entity.DynamicProxies.CashPayment_86783D165755C316A2F58A4343EEC4842907C5539AF24F0E64AEF498B15105C2
So my theory is that when AutoMapper tries to map CashPayment to DtoCashPayment and the payment passed in is of the proxy type AutoMapper sees it as a "non match" and then maps the generic Payment type. But since Payment is an abstract class AutoMapper bombs with a "System.InvalidOperationException: Instances of abstract classes cannot be created." exception.
所以我的理论是,当 AutoMapper 尝试将 CashPayment 映射到 DtoCashPayment 并且传入的付款是代理类型时,AutoMapper 将其视为“不匹配”,然后映射通用付款类型。但是由于 Payment 是一个抽象类,AutoMapper 会用“System.InvalidOperationException:无法创建抽象类的实例”来轰炸。例外。
So the question is: Is there a way for me to use AutoMapper to map EF POCO proxy objects to Dtos.
所以问题是:有没有办法让我使用 AutoMapper 将 EF POCO 代理对象映射到 Dtos。
采纳答案by oli
This answer comes 'a bit' late as I've just faced the same issue with EF4 POCO proxies.
这个答案来得有点晚,因为我刚刚在 EF4 POCO 代理上遇到了同样的问题。
I solved it using a custom converter that calls Mapper.DynamicMap<TDestination>(object source)to invoke the runtime type conversion, rather than the .Include<TOtherSource, TOtherDestinatio>().
我使用自定义转换器解决了这个问题,该转换器调用Mapper.DynamicMap<TDestination>(object source)调用运行时类型转换,而不是.Include<TOtherSource, TOtherDestinatio>().
It works fine for me.
这对我来说可以。
In your case you would define the following converter:
在您的情况下,您将定义以下转换器:
class PaymentConverter : ITypeConverter<Payment, DtoPayment> {
public DtoPayment Convert( ResolutionContext context ) {
return Mapper.DynamicMap<DtoPayment>( context.SourceValue );
}
}
And then:
进而:
Mapper.CreateMap<Payment, DtoPayment>().ConvertUsing<PaymentConverter>();
Mapper.CreateMap<CashPayment, DtoCashPayment>();
Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();
回答by chrislhardin
I also tried Olivier's example and got the same StackOverflow errors. I also tried subkamran's solution but not luck there as I am not using a base class from the entity model code generation. Automapper still blows up. Until I find a better solution, I just set the Context to not create Proxies when I create a Context object.
我还尝试了 Olivier 的示例并得到了相同的 StackOverflow 错误。我也尝试了 subkamran 的解决方案,但没有运气,因为我没有使用实体模型代码生成中的基类。Automapper 仍然会爆炸。在找到更好的解决方案之前,我只是在创建 Context 对象时将 Context 设置为不创建代理。
model.Configuration.ProxyCreationEnabled = false;
model.Configuration.LazyLoadingEnabled = true;
I would also like to see an answer to the problem perhaps using something build into Automapper...
我也想看到这个问题的答案,也许使用 Automapper 内置的东西......
UPDATE: The Pre-release of Automapper corrects this issue and allows for the mapping to cover a DynamicProxy with no extra configuration.
更新:Automapper 的预发布版更正了这个问题,并允许映射无需额外配置即可覆盖 DynamicProxy。
The release this works in is 2.2.1
这个作品的版本是 2.2.1
回答by kamranicus
Building on Olivier's response, I could not get his to work in my context... it kept going in an infinite loop and threw a StackOverflowException.
基于 Olivier 的回应,我无法让他在我的上下文中工作......它一直在无限循环中并抛出 StackOverflowException。
In this example, AbstractClassis my base class and AbstractViewModelis my base view model (not marked as abstractmind you).
在这个例子中,AbstractClass是我的基类,AbstractViewModel是我的基本视图模型(没有标记为abstract介意你)。
However, I did get it to work using this hackish looking converter:
但是,我确实使用这个看起来很黑的转换器让它工作了:
public class ProxyConverter<TSource, TDestination> : ITypeConverter<TSource, TDestination>
where TSource : class
where TDestination : class
{
public TDestination Convert(ResolutionContext context)
{
// Get dynamic proxy base type
var baseType = context.SourceValue.GetType().BaseType;
// Return regular map if base type == Abstract base type
if (baseType == typeof(TSource))
baseType = context.SourceValue.GetType();
// Look up map for base type
var destType = (from maps in Mapper.GetAllTypeMaps()
where maps.SourceType == baseType
select maps).FirstOrDefault().DestinationType;
return Mapper.DynamicMap(context.SourceValue, baseType, destType) as TDestination;
}
}
// Usage
Mapper.CreateMap<AbstractClass, AbstractViewModel>()
.ConvertUsing(new ProxyConverter<AbstractClass, AbstractViewModel>());
So, a DerivedClassAwill map normally, but a DynamicProxy_xxxwill also map properly as this code inspects its base type (DerivedClassA).
因此, aDerivedClassA将正常映射,但 aDynamicProxy_xxx也将正确映射,因为此代码检查其基本类型 ( DerivedClassA)。
Please, please, please show me that I don't have to do this crazy lookup crap. I don't know enough AutoMapper to fix Olivier's answer properly.
拜托,拜托,请告诉我,我不必做这种疯狂的查找废话。我不知道足够的 AutoMapper 来正确修复 Olivier 的答案。
回答by davesw
I ran into the same issue with Entity Framework proxies, but didn't want to switch to a pre-release version of AutoMapper. I found a simple if slightly ugly work around for version 2.2.0. I was trying to go from a DTO to an existing EF proxy object, and was getting errors about missing a mapping for the ugly proxy class name. My solution was to use an overload the specified the actual concrete types that I'd manually mapped:
我在使用 Entity Framework 代理时遇到了同样的问题,但不想切换到 AutoMapper 的预发布版本。我为 2.2.0 版找到了一个简单但略显丑陋的解决方法。我试图从一个 DTO 转到一个现有的 EF 代理对象,并且遇到了关于缺少丑陋代理类名的映射的错误。我的解决方案是使用指定的我手动映射的实际具体类型的重载:
Mapper.Map(dtoSource, entityDest, typeof(DtoClass), typeof(ConcreteEntityClass));
回答by Ilya Schukin
I've just faced the same problem with mapping dynamic EF proxies to ViewModels in MVC application.
我刚刚在 MVC 应用程序中将动态 EF 代理映射到 ViewModel 时遇到了同样的问题。
I found an easy solution using Mapper.DynamicMap()for this problem. Here is my code:
对于这个问题,我使用Mapper.DynamicMap()找到了一个简单的解决方案。这是我的代码:
Converting from Dynamic proxy to ViewModel class:
从动态代理转换为 ViewModel 类:
// dynamic proxy instance
WebService webService = _repWebService.GetAll().SingleOrDefault(x => x.Id == id);
//mapping
FirstStepWebServiceModel model = Mapper.DynamicMap<FirstStepWebServiceModel>(webService);
Converting from ViewModel class to EF Dynamic Proxy:
从 ViewModel 类转换为 EF 动态代理:
[HttpPost]
public ActionResult FirstStep(FirstStepWebServiceModel input)
{
// getting the dynamic proxy from database
WebService webService = _repWebService.GetAll().Single(x => x.Id == input.WebServiceId);
// mapping the input ViewModel class to the Dynamic Proxy entity
Mapper.DynamicMap(input, webService);
}
Hope this example help you
希望这个例子对你有帮助

