C# DTO List that consists of 2 other lists - c#

Firstly, apologies if this seems basic, I am new to C#/dotnet and if the answer to this questions is somewhere obvious please point me in the right direction.
I have a DTO class with the following code
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonImagesListView> LessonImages { get; set; }
public List<LessonInstructionCardListView> InstructionCards { get; set; }
}
public class LessonImagesListView
{
public long Id { get; set; }
public string Title { get; set; }
public ImageDetailView Image { get; set; }
public LessonImagesListView()
{
Image = new ImageDetailView();
}
}
public class LessonInstructionCardListView
{
public long Id { get; set; }
public string Instructions { get; set; }
}
So I have 2 distinct types of object that I attach to the lesson and send to the frontend.
I will add that in the future I might have 6 different types of object.
These Images, or Instructions are also going to be displayed in a certain order on the front end so instead of sending them all separately I wanted to combine them all and send them in a new List LessonAssetsListView for example.
How can i create Lists in a DTO that combine 2 other lists ?
OR ... is this something I even need to do here ... and can i just do all this in my service.
Help appreciated.

You could simply define a type that composes both your existing and send a List of them
public class LessonAsset
{
public LessonImagesListView Image {get;set; }
public LessonInstructionCardListView Instruction {get;set;}
}
and then
public class LessonDetailView : BaseResult
{
public long Id { get; set; }
public string Title { get; set; }
public List<LessonAsset> LessonAssets { get; set; }
}

Related

Interface with a list of interface, how to choose one type implemented by interface

This is my first question on StackOverflow, so please forgive and tell me if I'm doing something wrong.
Problem:
I write some kind of dictionary connected to DB and text files etc. nothing commercial, just learning. For better explanation it can be English-French.
I want to refactor the code to have possibility of use one "general" method to process entrance for English-French and French-English dictionary model. On the begining i made separate model for each of them(I will paste if necessary) and now i would like to make everything "universal". What I did till i stop:
public interface IWordModel
{
int Id { get; set; }
string Name { get; set; }
string Definition { get; set; }
}
class implementing IWordModel:
public class EnglishWordModel: IWordModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Definition { get; set; } = null;
}
public class FrenchWordModel : IWordModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Definition { get; set; } = null;
}
Interface implementing IWordModel and problematic List of this interface:
public interface IDictionairyModel<T> where T : IWordModel
{
int Id { get; set; }
T BaseWord { get; set; }
List<T> DerivativeWords { get; set; }
}
Class implementing IDicionairyModel
public class EnglishFrenchDictionairyModel<T>: IDictionairyModel where T : IWordModel
{
public int Id { get; set; }
public IWordModel BaseWord { get; set; } = new EnglishWordModel();
public List<IWordModel> DerivativeWords { get; set; } = = new
List<IWordModel>(new List<FrenchWordModel>());
}
public class FrenchDictionairyModel: IDictionairyModel<T> where T : IWordModel
{
public int Id { get; set; }
public IWordModel BaseWord { get; set; } = new FrenchWordModel();
public List<IWordModel> DerivativeWords { get; set; } = = new
List<IWordModel>(new List<EnglishWordModel>());
}
And my Question
How to make that i.e in FrenchDictionairyModel instance we will be able to define BaseWord only as FrenchWordModel and add to DerivativeWords list ONLY EnglishWordModel? I know it have something common with covariance and contrvariance but i dont have idea how to apply this here.
Is it above code have some sense from experienced coder point of view or it's look like OK only in my head? If answer is NO then how it should look like, what pattern should i use?
How to use it properly in other methods? As now i was using i.e
public List<EnglishFrenchDictionairyModel>
CreateEnglishFrenchEntrance(List<EnglishFrenchDictionairyModel> model){
( ... )}
but its already showing "Using generic type requires 1 type arguments".
Thanks and have a Great Day!
It sounds like you need two generic parameters - one to apply to BaseWord and one to apply to DerivativeWords:
public interface IDictionairyModel<T,U>
where T : IWordModel, U : IWordModel
{
int Id { get; set; }
T BaseWord { get; set; }
List<U> DerivativeWords { get; set; }
}
Then define your FrenchDictionaryModel as so:
public class FrenchDictionairyModel:
IDictionairyModel<FrenchWordModel, EnglishWordModel>
{
public int Id { get; set; }
public FrenchWordModel BaseWord { get; set; } = new FrenchWordModel();
public List<EnglishWordModel> DerivativeWords { get; set; } = new List<EnglishWordModel>();
}
Thanks D Stanley! it works fine, just need to add two where clauses for U and T like:
public interface IDictionairyModel<T,U>
where T : IWordModel,
where U : IWordModel {(...)}
But now i have another issue which i would like to implement here.
For example i would like to create some method which will be remove duplicates from List but i want to this to be ONE method for all class which implementing IDictionairyModel
public static List<IDictionairyModel<IWordModel, IWordModel>> RemoveDuplicates(this List<IDictionairyModel<IWordModel, IWordModel>> model)
{
(...) return model;
}
What I need to do to be able to use this extension method on
List<FrenchDictionairyModel> model = new List<FrenchDictionairymodel>();
model.RemoveDuplicates();
As for now it return error.
Should I make FrenchDictionairyModel also generic like:
public class PoznanPolishDictionairyModel<T,U> : IDictionairyModel<PoznanWordModel, PolishWordModel>
where T:IWordModel
where U:IWordModel
??? What is the proper way
Thanks a lot!!!
Have a wonderful Sunday!
Best Regards

Converting infinitely nested objects in .NET Core

EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?

How to: Nested Lists in SQLite-Net Extensions

How to: Do nested lists in sqlite-net-extensions
Answer Found: Keeping the question as an example of how to do it.
The problem i encountered was not sqlite-net-extensions related, but i'm keeping the question for context.
[Old Question]
I've got a problem with TwinCoders SQLite-net extensions.
I'm trying to insert a Series object into my database:
I'm using the Db.InsertWithChildren(SelectedSeriesObject,recursive:true) method.
The Series object is added accordingly with it's attributes.
All the Episodes are added as well, no problems there.
The problem is the BaseSeason.
It will only insert one Season object, which is (for some reason) the last Season Object of the list of Seasons in the Series
public class BaseSeries : BaseMedia
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[Indexed]
public int ShowId { get; set; }
public string FirstAirDate { get; set; }
public string LastAirDate { get; set; }
public string Status { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BaseSeason> Seasons { get; set; }
/// <summary>
/// TvShow = 0, Anime = 1
/// </summary>
public int SeriesType { get; set; }
}
public class BaseSeason
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(BaseSeries))]
public int SeasonId { get; set; }
public int SeasonNumber { get; set; }
public int NumberOfEpisodes { get; set; }
public string Plot { get; set; }
public string Poster { get; set; }
public string AirDate { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BaseEpisode> Episodes { get; set; }
[ManyToOne]
public BaseSeries BaseSeries { get; set; }
}
public class BaseEpisode
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(BaseSeason))]
public int EpisodeId { get; set; }
public string Title { get; set; }
public string Plot { get; set; }
public string Poster { get; set; } //still path
public string AirDate { get; set; }
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string SeriesName { get; set; }
[ManyToOne]
public BaseSeason BaseSeason { get; set; }
}
Is there anyone with experience regarding nested relationships in sqlite-net-extensions that knows how to make this work or see what i did wrong?
So regarding writing nested lists in sqlite-net-extensions:
My problem turned out the be related to how I handle the creation of these objects, this is by no means related to sqlite-net extensions. So my bad!
Which means that the questions example is valid and works. (I tested it of course)
Setting up the entities for the database:
The example shown in my question, with a Series class, Season class and Episode class, is the correct way of setting it up.
Inserting into the database:
If you're wondering how to insert an object similar to my Series object (with nested lists), use:
db.InsertWitchChildren(yourObject, recursion: true)
Here's an extended example:
public void AddSeries()
{
MediaDB.db.CreateTable<BaseSeries>();
MediaDB.db.CreateTable<BaseSeason>();
MediaDB.db.CreateTable<BaseEpisode>();
MediaDB.db.InsertWithChildren(SelectedSeries, recursion: true);
}
Side Note:
The example uses a static property on class with the connection string. Like so:
public class MediaDB
{
public static SQLiteConnection db => new SQLiteConnection(new SQLitePlatformGeneric(),"Media.db");
}
Refrain from doing this it is not really the best thing to do, since you should use using for the SQLiteConnection, making sure it's disposed once you're done with it.
more info on: sqlite-net-extentions
[UPDATE]: Further expansion of handling nested lists in sqlite-net extensions:
Deleting tables with children:
This is quite simple, but i spent a good hour and half figuring it out anyways.
Just use:
For lists/arrays: db.DeleteAll(yourCollection, recursion: true)
For single objects: db.Delete(yourObject, true);
As an exmaple: here's my implementation of a method that will delete a List
(BaseSeries is the class shown in the original question question):
public static void RemoveCollection<T>(List<T> collection)
{
using (db)
{
if (typeof(T) == typeof(BaseMovie))
{
db.DeleteAll(collection);
}
if (typeof(T) == typeof(BaseSeries))
{
db.DeleteAll(collection, recursion: true);
}
}
}
The BaseMovie class is a simple single entity, recursion is not needed since it holds no children.

Object optimization and grouping

I have objects that are defined this way:
class BFull
{
public string ImageID { get; set; }
public List<string> Tapes { get; set; }
}
class OptSet
{
public int SetID { get; set; }
public List<string> Tapes { get; set; }
public List<string> Images { get; set; }
}
The BFull object is DB defined and I can't alter it much. The second one is the wanted result of my actions. And the problem is:
I need to optimize those BFulls into OptSets with a limitation that any given OptSet can have max 24 distinct tapes and consist only complete BFulls. Can anybody help how to achieve that?

Class and Struct as Projectables

Many a times i have to do select required fields from a class as in case of selected desired fields from Table in sql.
So i was thinking of making my class and struct as Projectables.
Here is what I want to achieve.
public class Email
{
public string Subject { get; set; }
public string To { get; set; }
public string Cc { get; set; }
public string Bcc { get; set; }
public string Body { get; set; }
public DateTime ReceivedDate { get; set; }
}
public class EmailProjection
{
// instead of this
//public string Subject { get; set; }
//public DateTime ReceivedDate { get; set; }
// I want to do this
Email.Project(Subject,ReceivedDate);
}
public class EntryPoint
{
static void Main()
{
var emailList = new List<Email>();
/* populate emails here from source*/
// I want to do this
List<EmailProjection> emailProjectionList = emailList.Project(EmailProjection).ToList();
// rather than
List<EmailProjection> emailProjectionList= emailList.Select(email=>new {email.Subject,email.ReceivedDate}).ToList();}
}
Can somebody help me as to how to go about this? Hints?? Is it achievable?
You can have a look at Automapper: https://github.com/AutoMapper/AutoMapper.
It is a library to map DTO based on naming conventions and rules.
Take a look in the wiki there is a Projection page, that could be the one you are looking for.
Just for connect with your example, you can eventually write code like this:
Mapper.Map<EMail, EmailProjection>(yourObjects);

Categories