2016-04-26 13 views
0

Ich habe eine Sammlung in MongoDb, die Objekte enthält, die von einer Klasse "FeedItemBase" abgeleitet sind. Wenn ich diese Auflistung abfrage, gebe ich eine Liste von FeedItemBase-Objekten zurück.MongoDb abstrakte Sammlung und Downcasting

//This is my collection property in the RepoBase abstract 
public IMongoCollection<T> Collection { get; set; } 

//This is what my repo looks like, therefore my Collection is T = UserFeed 
public class UserFeedsRepo : RepoBase<UserFeed>, IAsyncRepo<UserFeed> 
{...The method below lives in this repo...} 

public async Task<IEnumerable<FeedItemBase>> GetFeedItems(string userId, int skip, int limit) 
{ 
    try 
    { 
     var results = await Collection 
      .Aggregate() 
      .Match(x => x.User.Id == userId) 
      .Unwind<UserFeed, UnwindedFeedItems>(x => x.Items) 
      .SortByDescending(x => x.Items.DatePosted) 
      .Skip(skip) 
      .Limit(limit) 
      .ToListAsync() 
      .ConfigureAwait(false); 
     return results.Select(x => x.Items); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("An exception occured in GetFeedItems", ex); 
    } 
} 

Was ist in Ordnung. Wenn ich diese Objekte in diesem Formular (DTO) an meinen Client von WebApi als Json übergebe, werden sie korrekt in ihren abgeleiteten Formularen am Client mit $ type serialisiert.

Allerdings gibt es einen Punkt, wo ich diese DTOs in einigen Viewmodels, um injizieren müssen Informationen weitergeben, die nicht in der Datenbank gespeichert wird, in ihrer einfachsten Form:

FeedItemImage derives from FeedItemBase 
FeedItemComment derives from FeedItemBase 

Der einzige Unterschied zwischen Die 2 Objekte sind "ImageUrl" bzw. "Comment".

Ich habe Probleme beim Umwandeln der Auflistung von FeedItemBase-Objekten in ihre konkreten Formen und ich kann nicht scheinen, um einen sauberen Weg um es herum zu denken. Ich brauche sie in ihren konkreten Formen, damit ich, wenn sie in die ViewModel-Konstruktoren eingefügt werden, auf die Eigenschaften Comment und ImageUrl zugreifen kann.

private async Task<List<FeedItemViewModelBase>> GetFeedItemViewModels(IEnumerable<Models.DTO.Feed.FeedItemBase> feedItems) 
{ 
    try 
    { 
     List<FeedItemViewModelBase> viewModels = new List<FeedItemViewModelBase>(); 
     //This is where it is currently bombing out 
     var commentItems = (IEnumerable<Models.DTO.Feed.FeedItemComment>)feedItems.Where(x => x.ObjectType == "FeedItemComment"); 
     var imageItems = (IEnumerable<Models.DTO.Feed.FeedItemImage>)feedItems.Where(x => x.ObjectType == "FeedItemImage"); 

     //These 2 lines return populate view models to be added to the list to be returned 
     var commentViewModelsTask = GetFeedItemCommentViewModels(commentItems).ConfigureAwait(false); 
     var imageViewModelsTask = GetFeedItemImageViewModels(imageItems).ConfigureAwait(false); 

     viewModels.AddRange(await commentViewModelsTask); 
     viewModels.AddRange(await imageViewModelsTask); 

     return viewModels; 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("There was a problem retrieving feed item viewmodels", ex); 
    } 
} 

Kann mir jemand dabei helfen? Oder sag mir, ob es einen besseren Weg gibt.

Vielen Dank im Voraus

+1

Ich denke, das Problem Das heißt, Sie müssen jedes Objekt einzeln in der Liste darstellen. Sie können 'Liste ' nicht in 'Liste ' umwandeln, Sie müssen 'foreach (b in listOfBaseObjects) {newList.Add ((b wie abgeleitet));}'. – Quantic

+0

Doh! Danke Quantic, du hast Recht. Ich habe linq verwendet, um jeden Gegenstand zu wirken - gezeigt in der Frage update – pieperu

+0

Sie können die Antwort in einer tatsächlichen Antwort anstatt editieren. Eigentlich denke ich, dass sie das bevorzugen. – Quantic

Antwort

0

Die Lösung wie Quantic wurde darauf hingewiesen, jedes Element in der Liste zu werfen, anstatt zu versuchen, die gesamte Sammlung zu werfen:

var commentItems = feedItems 
    .Where(x => x.ObjectType == "FeedItemComment") 
    .Select(x => (Models.DTO.Feed.FeedItemComment)x); 

Dank Quantic