2016-12-29 3 views
1

In meinem Projekt habe ich eine LINQ abfragbare (eigentlich eine EF6-Sammlung), die ich in eine Sammlung von Datenübertragungsobjekten konvertieren muss. Ich verwende AutoMapper während des gesamten Projekts, vor allem wegen seiner Fähigkeit, eine Typ-Projektion durchzuführen, wodurch die Menge an SQL reduziert wird, die von der Linq-Abfrage generiert wird.AutoMapper löst Ausnahme bei der Projektion auf NULL-Enum

Aber ich habe ein kleines Problem mit einer meiner DTO-Klassen. Die zugehörige Datenbankspalte enthält eine Nullable-Zeichenfolge, die ich einer nullfähigen Enumeration zuordnen möchte. Zur Laufzeit wird jedoch eine Ausnahme ausgelöst

Kein Zwangsoperator ist zwischen den Typen 'System.String' und 'System.Nullable`1 [AutomapperEnumTest.Method] definiert.

Hier ist ein komplettes Testprogramm, das das Problem veranschaulicht: (siehe .Net Fiddle)

using System; 
using System.Linq; 
using AutoMapper; 
using AutoMapper.QueryableExtensions; 

namespace AutomapperEnumTest 
{ 
    public class Program 
    { 
     public static void Main() 
     { 
      Configure(); 
      var src = new SourceType[] { new SourceType { Name = "Rob", MethodName = "AUTO" } }; 
      var results = src.AsQueryable() 
         .ProjectTo<DestType>(); 

      foreach(var item in results) 
      { 
       Console.WriteLine(String.Format("DestType Name={0} Method={1}", item.Name, item.Method)); 
      } 
      Console.WriteLine("Done"); 
     } 

     private static void Configure() 
     { 
      Mapper.Initialize(cfg => 
      { 
       cfg.CreateMap<string, Method?>().ProjectUsing(src => src == "MANUAL" ? Method.MANUAL : Method.AUTO); 
       cfg.CreateMap<SourceType, DestType>() 
        .ForMember(dest => dest.Method, opt => opt.MapFrom(src => src.MethodName)); 
      }); 
     } 
    } 

    public enum Method 
    { 
     MANUAL=0, 
     AUTO=1 
    } 

    public class DestType 
    { 
     public string Name {get; set; } 
     public Method? Method {get; set; } 
    } 

    public class SourceType 
    { 
     public string Name {get; set; } 
     public string MethodName {get; set; } 
    } 
} 

Nun, wenn ich die Eigenschaft Method?-Method es funktioniert ändern (diese Änderung in .Net Fiddle sehen). Aber ich möchte das nicht tun, also ist meine Frage, wie informiere ich Linq/AutoMapper, dass es meine ProjectUsing für die Nullable enum verwenden sollte?

Vielen Dank.

Antwort

1

Das gleiche passiert im neuesten AutoMapper v5.2.0.

Nach dem Quellcode suchen, denke ich es, weil aus unerfindlichen Gründen NullableExpressionBinder Priorität als CustomProjectionExpressionBinder gegeben ist höher um einen Fehler in der ExpressionBuilder Klasse ist (und andere), so dass im Grunde, wenn Sie nicht Nullable Type Karte, das alle auf NULL-Werte zulassen Die benutzerdefinierten Zuordnungen werden ignoriert.

Ich würde vorschlagen, dass Sie es auf ihrem Repository melden. Bis dahin könnte ich Ihnen die folgende Workaround (Hack) vorschlagen. Fügen Sie die folgende benutzerdefinierte Klasse in Ihrem Projekt:

using System.Linq.Expressions; 
using System.Reflection; 
using AutoMapper; 
using AutoMapper.QueryableExtensions; 
using AutoMapper.QueryableExtensions.Impl; 

class NullableExpressionBinderEx : IExpressionBinder 
{ 
    public static void Install() 
    { 
     var bindersField = typeof(ExpressionBuilder).GetField("Binders", BindingFlags.NonPublic | BindingFlags.Static); 
     var binders = (IExpressionBinder[])bindersField.GetValue(null); 
     binders[0] = new NullableExpressionBinderEx(); 
    } 
    IExpressionBinder baseBinder = new NullableExpressionBinder(); 
    private NullableExpressionBinderEx() { } 
    public bool IsMatch(PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionResolutionResult result) 
    { 
     if (propertyTypeMap != null && propertyTypeMap.CustomProjection != null) 
      return false; 
     return baseBinder.IsMatch(propertyMap, propertyTypeMap, result); 
    } 
    public MemberAssignment Build(IConfigurationProvider configuration, PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary<ExpressionRequest, int> typePairCount) 
    { 
     return baseBinder.Build(configuration, propertyMap, propertyTypeMap, request, result, typePairCount); 
    } 
} 

fügen Sie dann die folgende Zeile in Configure Methode:

NullableExpressionBinderEx.Install(); 

und das Problem gelöst werden soll.

+1

Vielen Dank für die Bereitstellung einer solchen vollständigen Antwort. Ich habe es getestet und das löst das Problem. – Rob

1

Sie können Methodenname manuell zu Method zuordnen, es sei denn, ich vermisse etwas in Ihrer Frage.

private static void Configure() 
{ 
    Mapper.Initialize(cfg => 
    { 
     cfg.CreateMap<SourceType, DestType>() 
      .ForMember(dest => dest.Method, opt => opt.MapFrom(src => 
       src.MethodName == "MANUAL" ? Method.MANUAL : Method.AUTO)); 
    }); 
} 
+0

Vielen Dank @Win, Ihre Lösung funktioniert in diesem einfachen Beispiel. Ich habe nicht daran gedacht, das zu versuchen, weil die Enumeration in der tatsächlichen Anwendung an mehreren Stellen verwendet wird, so dass ich bevorzuge, dass der Typ eine eigene Mapping-Konfiguration hat (z. B. eine "ProjectUsing" -Konfiguration). Weißt du, ob das möglich ist, und wenn nicht, was stört dich? – Rob

+0

In meinem zweiten .Net Fiddle-Beispiel werden Sie sehen, dass es eine globale Zuordnung von 'String' zu der' Method'-Enumeration gibt. Dies funktioniert gut, aber die gleiche Technik scheint nicht für 'System.Nullable ' zu funktionieren. – Rob

+0

Es ist etwas falsch in *** ProjectTo *** Erweiterung Methode 'src.AsQueryable(). ProjectTo ()'. Ihr Code arbeitet mit 'var results = src.Select (Mapper.Map );' – Win

Verwandte Themen