4

I try to create a timeline collection that contians multiple types. I have no problem to insert the type or read a specific type. But when i want a list of all types for a specific user, then i got problem.

public interface ITimelineItem
{
    public string EventType { get; set; }
    public string EventId { get; set; }
    public Guid UserId { get; set; }
}

public class TimelineItemBase
{
    public string EventType { get; set; }
    public string EventId { get; set; }
    public Guid UserId { get; set; }
    public List<MediaInfo> Media { get; set; }
}

public class AlbumEvent : TimelineItemBase, ITimelineItem
{
    public MediaAlbum Album { get; set; }
}

public class BirthdayEvent : TimelineItemBase, ITimelineItem
{
}

public class BlogPostEvent : TimelineItemBase, ITimelineItem
{
    public BlogPost Post { get; set; }
}

public static class TimelineRepo
{
    private static IMongoCollection<T> GetCollection<T>() where T : ITimelineItem
    {
        return Connection.Database.GetCollection<T>("Timeline");
    }

    public static async Task Add<T>(T data) where T : ITimelineItem
    {
        data.EventType = typeof(T).Name;

        var coll = GetCollection<T>();
        await coll.InsertOneAsync(data);
    }

    public static async Task<List<T>> GetEventsByUserId<T>(Guid userId) where T : ITimelineItem
    {
        return await GetCollection<T>().Find(p => p.UserId == userId).ToListAsync();
    }
}


public class GenerateTimeline
{
    public static async Task<List<ITimelineViewModel>> GetTimeline(Guid userId)
    {
        var items = await TimelineRepo.GetEventsByUserId<???>(userId);

        foreach (var item in items)
        {
            if (item is BirthdayEvent be)
            {
                // do work
            }
            else if (item is BlogPostEvent bp)
            {
                // do work
            }
            else if (item is AlbumEvent ae)
            {
                // do work
                ae.Album.Header
            }
        }
    }
}


[HttpGet("/api/user/{userid}/timeline"), Authorize]
public async Task<List<ITimelineViewModel>> GetTimeline(Guid userId)
{
    return await GenerateTimeline.GetTimeline(userId);
}

How can I get a list containing different types for a user? Or is this a bad way to create a timeline for users?

5
  • Yes, there's no way for any kind of serialiser to choose the correct type when reading the JSON back so this wouldn't work. Commented Jun 12, 2022 at 11:12
  • I understand that, but i store the type in EventType so it should be possible to serialise it back to the correct object type? Commented Jun 12, 2022 at 15:47
  • Yes, but how would you know which type to deserialise it to beforehand? Commented Jun 12, 2022 at 18:46
  • 5
    MongoDB can deal with multiple document types that are derived from a base class (polymorphism). You are basically implementing it yourself. Maybe this link can help: mongodb.github.io/mongo-csharp-driver/2.8/reference/bson/… Commented Jun 14, 2022 at 8:05
  • What i did was to read all as BsonDocument, loop all items and check property EventType and then select the correct class, example: foreach(var item in items) { var type = item["EventType"]; if(type == nameOf(BirthdayEvent) list.Add(BsonSerializer.Deserialize<BirthdayEvent>(item)); } Is that a bad solution? Commented Jun 14, 2022 at 18:12

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.