如何找到基于与AutoMapper扁平属性的名称源属性

编程入门 行业动态 更新时间:2024-10-28 12:21:06
本文介绍了如何找到基于与AutoMapper扁平属性的名称源属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我使用AutoMapper,我想它根据映射(扁平)目标属性的名称,追溯源属性。

I'm using AutoMapper and I'd like it to trace back a source property based on the name of the mapped (flattened) destination property.

这是因为我的MVC控制器具有一个对应的属性的,它需要提供一个服务调用的名称进行排序的目的。该服务需要知道的映射源于属性的名称(和控制器不应该知道),以执行到实际排序的数据仓库适当的呼叫。

This is because my MVC controller has the name of a mapped property that it needs to provide to a service call that for sorting purposes. The service needs to know the name of the property that the mapping originated from (and the controller is not supposed to know it) in order to perform a proper call to the repository that actually sorts the data.

例如:

[Source.Address.Zip code]映射到[Destination.AddressZip code]

[Source.Address.ZipCode] maps to [Destination.AddressZipCode]

然后

跟踪AddressZip code回[Source.Address.Zip code]

Trace "AddressZipCode" back to [Source.Address.ZipCode]

这是一些AutoMapper能为我做什么或做我需要求助于挖掘AutoMapper的映射数据?

Is this something that AutoMapper can do for me or do I need to resort to digging into AutoMapper's mapping data?

更新

吉米·博加德告诉我,这应该是可能的,但没有明显的方式。它需要加载类型地图,通过它。我看着它简单,但似乎我需要访问内部的类型去所需要做反向映射属性映射信息。

Jimmy Bogard told me that this should be possible but not in an obvious manner. It requires loading the type map and going through it. I've looked into it briefly but it seems that I need access to internal types to get to the property mapping information that is required to do reverse mapping.

更新2

我已经决定提供一些更多的细节。

I've decided to provide some more details.

当我加载的类型映射表,我发现有在这两个源值解析器为隐邮编code映射:

When I load up the type map, I find that there are two source value resolvers in it for the implicit ZipCode mapping:

  • 在 AutoMapper.Internal.PropertyGetter ,获取地址。
  • 在 AutoMapper.Internal.PropertyGetter 是可以获得邮编code。
  • a AutoMapper.Internal.PropertyGetter that gets the Address.
  • a AutoMapper.Internal.PropertyGetter that gets the ZipCode.

当我有一个明确的映射(有指定的lambda EX pression),我觉得没有源值解析,但自定义解析:

When I have an explicit mapping (that has a lambda expression specified), I find no source value resolver but a custom resolver:

  • 在 AutoMapper.DelegateBasedResolver<公司,串> ,我想保持我的显式映射的lambda EX pression
  • a AutoMapper.DelegateBasedResolver<Company,string> that I think holds my explicit mapping lambda expression.

不幸的是,这些解析器是内部的,所以我只能通过反射(我真的不想这样做),或者通过改变AutoMapper源$ C ​​$ C访问它们。

Unfortunately these resolvers are internal so I can only access them through reflection (which I really don't want to do) or by changing the AutoMapper source code.

如果我能访问它们,我既可以由通过价值解析器,或通过检查自定义冲突解决行走解决这个问题,虽然我对此表示怀疑,这将导致我回到映射的lambda EX pression,我需要建立在不平属性名(实际上是一系列的属性名称由点分隔)。

If I could access them, I could solve the problem by either walking through the value resolvers or by inspecting the custom resolver although I doubt it that would lead me back to the mapping lambda expression which I need to build the unflattened property name (actually a series of property names separated by dots).

推荐答案

暂时,我写的,可以从一个连接的产业链决定发起产业链一个辅助类。 Ofcourse,这将成为过时的时候AutoMapper得到一个功能,做这种事情。

For the time being, I wrote a helper class that can determine the originating property chain from a concatenated property chain. Ofcourse, this will become obsolete when AutoMapper gets a feature to do this kind of thing.

using System.Globalization; using System.Reflection; /// <summary> /// Resolves concatenated property names back to their originating properties. /// </summary> /// <remarks> /// An example of a concatenated property name is "ProductNameLength" where the originating /// property would be "Product.Name.Length". /// </remarks> public static class ConcatenatedPropertyNameResolver { private static readonly object mappingCacheLock = new object(); private static readonly Dictionary<MappingCacheKey, string> mappingCache = new Dictionary<MappingCacheKey, string>(); /// <summary> /// Returns the nested name of the property the specified concatenated property /// originates from. /// </summary> /// <param name="concatenatedPropertyName">The concatenated property name.</param> /// <typeparam name="TSource">The mapping source type.</typeparam> /// <typeparam name="TDestination">The mapping destination type.</typeparam> /// <returns> /// The nested name of the originating property where each level is separated by a dot. /// </returns> public static string GetOriginatingPropertyName<TSource, TDestination>(string concatenatedPropertyName) { if (concatenatedPropertyName == null) { throw new ArgumentNullException("concatenatedPropertyName"); } else if (concatenatedPropertyName.Length == 0) { throw new ArgumentException("Cannot be empty.", "concatenatedPropertyName"); } lock (mappingCacheLock) { MappingCacheKey key = new MappingCacheKey(typeof(TSource), typeof(TDestination), concatenatedPropertyName); if (!mappingCache.ContainsKey(key)) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; List<string> result = new List<string>(); Type type = typeof(TSource); while (concatenatedPropertyName.Length > 0) { IEnumerable<PropertyInfo> properties = type.GetProperties(bindingFlags).Where( n => concatenatedPropertyName.StartsWith(n.Name)).ToList(); if (properties.Count() == 1) { string match = properties.First().Name; result.Add(match); concatenatedPropertyName = concatenatedPropertyName.Substring(match.Length); type = type.GetProperty(match, bindingFlags).PropertyType; } else if (properties.Any()) { throw new InvalidOperationException( string.Format( CultureInfo.InvariantCulture, "Ambiguous properties found for {0} on type {1}: {2}.", concatenatedPropertyName, typeof(TSource).FullName, string.Join(", ", properties.Select(n => n.Name)))); } else { throw new InvalidOperationException( string.Format( CultureInfo.InvariantCulture, "No matching property found for {0} on type {1}.", concatenatedPropertyName, typeof(TSource).FullName)); } } mappingCache.Add(key, string.Join(".", result)); } return mappingCache[key]; } } /// <summary> /// A mapping cache key. /// </summary> private struct MappingCacheKey { /// <summary> /// The source type. /// </summary> public Type SourceType; /// <summary> /// The destination type the source type maps to. /// </summary> public Type DestinationType; /// <summary> /// The name of the mapped property. /// </summary> public string MappedPropertyName; /// <summary> /// Initializes a new instance of the <see cref="MappingCacheKey"/> class. /// </summary> /// <param name="sourceType">The source type.</param> /// <param name="destinationType">The destination type the source type maps to.</param> /// <param name="mappedPropertyName">The name of the mapped property.</param> public MappingCacheKey(Type sourceType, Type destinationType, string mappedPropertyName) { SourceType = sourceType; DestinationType = destinationType; MappedPropertyName = mappedPropertyName; } } }

下面是一个使用示例:

class TestEntity { public Node Root {get; set;} } class Node { public string Leaf {get; set;} } class TestFlattenedEntity { public string RootLeaf {get; set;} } string result = ConcatenatedPropertyNameResolver.GetOriginatingPropertyName<TestEntity, TestFlattenedEntity>("RootLeaf"); Assert.AreEqual("Root.Leaf", result);

更多推荐

如何找到基于与AutoMapper扁平属性的名称源属性

本文发布于:2023-11-09 10:49:17,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1572172.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:属性   名称   AutoMapper

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!