0

I have a collection in MongoDb which contains objects which are derived from a class "FeedItemBase". When i query this collection, i return a list of FeedItemBase objects.

//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);
    }
}

Which is fine. If i pass these objects in this form (DTO) to my client from WebApi as Json, they are correctly serialized into their derived forms at client using $type.

However, there is a point where I need to inject these DTos into some ViewModels in order to pass down information that is not saved in my database, in their simplest forms:

FeedItemImage derives from FeedItemBase
FeedItemComment derives from FeedItemBase

The only different between the 2 objects is "ImageUrl" and "Comment" respectively.

I am having trouble converting the collection of FeedItemBase objects to their concrete forms and I can't seem to think of a clean way around it. I need them i their concrete forms so that when injected into the ViewModel constructors I can access the Comment and ImageUrl properties.

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);
    }
}

Can someone help me with this? Or tell me if there is a better way of going about it.

Thanks in advance

pieperu
  • 2,662
  • 3
  • 18
  • 31
  • 1
    I think the problem is that you have to cast each object in the list separately. You cannot cast `List` to `List`, you have to `foreach (b in listOfBaseObjects) { newList.Add((b as derived));}`. – Quantic Apr 26 '16 at 16:13
  • Doh! Thanks Quantic, you are correct. I used linq to cast each item - Shown in the question update – pieperu Apr 28 '16 at 09:45
  • You can post the answer in an actual answer instead of editing. Actually I think they prefer that. – Quantic Apr 28 '16 at 14:42

1 Answers1

0

The solution as Quantic pointed out was to cast each item in the list rather than trying to cast the entire collection:

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

Thanks Quantic

pieperu
  • 2,662
  • 3
  • 18
  • 31