2016-07-28 6 views
-1

Ich habe den folgenden Satz von Klassen (nur in einer Richtung, von Data* bis Api*) zuzuordnen:Prevent AutoMapper Zeichenfolge als Sammlung in LINQ ProjectTo zu behandeln

// Top level 

public class DataEntity 
{ 
    public NestedDataEntity Nested { get; set; } 
    // ... other primitive/complex properties 
} 

public class ApiEntity 
{ 
    public NestedApiEntity Nested { get; set; } 
    // ... other primitive/complex properties 
} 

// Nested level 

public class NestedDataEntity 
{ 
    public string Items { get; set; } 
} 

public class NestedApiEntity 
{ 
    public IEnumerable<ApiSubItem> Items { get; set; } 
} 

public class ApiSubItem 
{ 
    // there are properties here. Not needed for the sake of example 
} 

Mapping innerhalb eines Profile wie in konfiguriert ist, das folgende Stück Code:

// mapping profile 

public class MyCustomProfile : Profile 
{ 
    public MyCustomProfile() 
    { 
    CreateMap<DataEntity, ApiEntity>(); 
    CreateMap<NestedDataEntity, NestedApiEntity>(); 

    CreateMap<string, IEnumerable<ApiSubItem>>() 
     .ConvertUsing<TextToSubItemsConverter>(); 
    } 
} 

// type converter definition 

public class TextToSubItemsConverter : 
    ITypeConverter<string, IEnumerable<ApiSubItem>> 
{ 
    public IEnumerable<ApiSubItem> Convert(
     string dataItems, IEnumerable<ApiSubItem> apiItems, ResolutionContext context) 
    { 
    // actually, deserialize & return an ApiSubItem[] 
    // here just return some fixed array 

    return new ApiSubItem[] 
    { 
     new ApiSubItem(), 
     new ApiSubItem(), 
     new ApiSubItem(), 
    }; 
    } 
} 

// Main 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
    Mapper.Initialize(cfg => 
    { 
     cfg.AddProfile<MyCustomProfile>(); 
    }); 

    Mapper.AssertConfigurationIsValid(); 

    DataEntity dataEntity = new DataEntity() 
    { 
     Nested = new NestedDataEntity() 
     { 
     Items = "Ignored text", 
     }, 
    }; 

    // This maps ok, no issues 
    ApiEntity apiEntity = Mapper.Map<DataEntity, ApiEntity>(dataEntity); 

    IQueryable<DataEntity> dataEntities = new[] { dataEntity }.AsQueryable(); 

    // This exposes the System.Char to ApiSubItem issue 
    ApiEntity apiEntityProjected = dataEntities.ProjectTo<ApiEntity>().First(); 
    } 
} 

Mapping Konfiguration geht Erstvalidierung beim Start, aber dann, wenn eine tatsächliche Mapping erforderlich ist ich Ausnahme:

System.InvalidOperationException: Fehlende Zuordnung von System.Char zu my.whatever.namespace.ApiSubItem. Erstellen Sie mit Mapper.CreateMap.

Wenn ich zwischen string und IEnumerable<ApiSubItem>, Erstvalidierung beschwert sich über den gleichen Kontext vollständig die Konfiguration auslassen:

Kontext: Mapping von Typ System.Char my.whatever.namespace.ApiSubItem

Wenn es hinzugefügt wird, scheint es, dass es nicht von AutoMapper aufgenommen wird.

Die Zuordnung erfolgt in einem statischen Kontext durch einen ProjectTo<ApiEntity>()-Aufruf über die LINQ-Abfrage über DbSet<DataEntity>. Ich habe überprüft, dass der Konverter keine Abhängigkeit erfordert, nur für den Fall.

AutoMapper ist 5.0.2 und wird in einer MVC API-Webanwendung unter ASP.Net Core 1 RTM ausgeführt.

Ich habe ähnliche Fragen hier auf SO überprüft, aber ohne Glück. Weiß jemand, wie man diese Art von Szenario funktioniert? Ich denke, ich bin nicht der erste, der versucht, (Auto) von einer string zu einer Sammlung zu mappen. TA

EDIT hinzugefügt beide versagen und nicht versiegende Fall zu Beispiel

EDIT 2 Nach weiteren suchen, schlug irgendwo jemand das Feld zu ignorieren und führen Mapping in AfterMap(). Mit diesem Profil wird keine Ausnahme ausgelöst, aber resultierende Items Feld ist null:

CreateMap<DataEntity, ApiEntity>(); 
CreateMap<NestedDataEntity, NestedApiEntity>() 
    .ForMember(api => api.Items, options => options.Ignore()) 
    .AfterMap((data, api) => 
    { 
     api.Items = Mapper.Map<IEnumerable<ApiSubItem>>(data.Items); 
    }); 

CreateMap<string, IEnumerable<ApiSubItem>>() 
    .ConvertUsing<TextToSubItemsConverter>(); 

EDIT 3 umformuliert Frage Titel, um es präziser für die Projektion

+0

Sie können die Zeichenfolge nicht der Sammlung zuordnen. In diesem Fall müssen Sie die Datei items.propertyname packen, deren Rückgabetyp Zeichenfolge ist. weil automapper arbeiten eins zu eins Zuordnung –

+0

können Sie eine [SSCCE] (http://sscce.org/) –

+0

@PankajGupta können Sie mir bitte noch einmal sagen, ich kann es nicht bekommen. – superjos

Antwort

0

ich denke, die eigentliche Antwort entlang der Linien von "Projektionen und Konverter/Resolver spielen nicht gut zusammen". Von AutoMapper Queryable.Extensions wiki:

Nicht alle Mapping-Optionen unterstützt werden können, wie der Ausdruck generiert wird, muss von einem LINQ-Provider interpretiert werden. [...]

Nicht unterstützt:

  • [...]
  • Vorher/AfterMap,
  • Individuelle Resolvern
  • Typ Individuelle Wandler

EDIT Umgehung:
In diesem speziellen Szenario, ich habe ein nützlich sein später gefunden zu haben DTO-Zwischenelement, das weitere Felder erfassen kann, die für die endgültige API-Entität nicht benötigt werden, aber für die Geschäftslogik weiterhin benötigt werden.

In einer solchen DTO-Entity verließ ich das string Feld wie in DataEntity, so dass ich Projektion verwenden konnte und AutoMapper/LinqToSQL nur benötigte Felder aus der Datenbank greifen lassen.

Dann könnte ich zwischen DTO-Entität und API-Entität, die sich bereits im Speicher befindet, eine zweite Zuordnung anwenden, die auch den benutzerdefinierten Konverter für die string ==> IEnumerable<ApiSubItem>-Zuordnung nutzt. HTH

Verwandte Themen