I have not worked with EF for a while.
As an exercise, I am writing a core web api
that allows keeping track of a user medias.
A media can be a postcard, a photo album, a recording, a book...
I would like to know what is the way to go/best practice in writing the Add (createMedia) method:
[HttpPost]
public async Task<ActionResult<bool>> Add(Media media)
My model is comprised of several specific classes representing one type of media - like Postcard, Photoalbum, recording, etc. In addition, there is a Media type - which contains shared properties among all media types:
public class Media
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public MediaType Type { get; set; }
public bool InUse { get; set; }
public string Date { get; set; } //yyyy-mm-dd
public string Owner { get; set; }
}
As an example of one of the specific media types:
public class Postcard
{
[ForeignKey("Id")]
public int MediaId { get; set; }
public string From { get; set; }
public string To { get; set; }
public string Place { get; set; }
public string Language { get; set; }
}
I designed my EntityFramework
db to consist of a 1-1 relation between Media and the relevant specific media table.
What is the best practice in writing the Add method ? Should it receive a Media object, and based on MediaType
create the respective type ? I started with this approach, and had the action receive a second parameter named detailsJson
, which I would parse and fill the respective object using reflection, but figured out that POST
binding will not bind 2 objects.
I'm not well versed in design patterns.
Should there exist as many AddBook, AddPostcard... as many media types ?
I understand all models should be POCO objects
, without inheritance.
I read about DTOs
, but does not see how it helps me here.
-
Firstly, could you provide the code of the MediaType-Class/-Struct/-Enum? A Generic Media-Base-Controller, and an IMedia-Interface could help, to prevent duplicating code.Nikolaus– Nikolaus2020年07月13日 21:03:21 +00:00Commented Jul 13, 2020 at 21:03
-
My concern was that POCO objects should not, theoretically have inheritance. I read this. I then realized I should be using composition in each of the specialized types adding a Media object as a navigation property to each. This way I achieve no code duplication while following EF practices. Am checking...Veverke– Veverke2020年07月13日 21:07:03 +00:00Commented Jul 13, 2020 at 21:07
-
I understand, but that's not what I meant. If you could show the Code of your MediaType and of how theoretically your Post-Method would look like, I can show you in an answer, what I meant.Nikolaus– Nikolaus2020年07月14日 11:47:29 +00:00Commented Jul 14, 2020 at 11:47
-
I don't have time to write an answer right now, but look into table-per-type mapping in EF Core, which enables you to use actual inheritance as opposed to 1-1 related entities. If you use TPT, the range of viable answers shifts in favor of a more standard OOP approach.Flater– Flater2021年08月10日 08:33:26 +00:00Commented Aug 10, 2021 at 8:33
1 Answer 1
If there should be separate methods for adding postcards, books and so on depends on the business context of your application. Go back to the business requirements and see if:
- Adding media items is a primary or a side activity/requirement for the users
- Media of different types are explicitly distinguished- for example is there a business requirement stating that books should be added from one place, photos from another
- Is there any reason to worry about the way adding books is going to change from adding photos, for example
If you answer positively to these questions it would be wise to separate the adding methods for different media types.
Looking at the sample Media and PostCard models you've defined it looks like they should definitely be added separately as they consist of different data attributes and look like they could change at any given moment.
As a side note: Your Media model seems to be the principal in this relationship, but to me it looks like a pure value object which should be an attribute of the concrete media types. A redesign of your sample models could look like this:
public class MediaAttributesValueObject
{
[Key]
//kept as a persistance detail
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool InUse { get; set; }
public string Date { get; set; } //yyyy-mm-dd
public string Owner { get; set; }
}
public class PostcardEntity
{
[Key]
public int Id { get; set; }
[ForeignKey("Id")]
public int MediaAttributesValueObjectId { get; set; }
public MediaType Type => MediaType.PostCard
public string From { get; set; }
public string To { get; set; }
public string Place { get; set; }
public string Language { get; set; }
}
Note that I've added ValueObject and Entity suffixes to highlight model types
The relationship would still be configured as 1-to-1, but in the opposite way with the specific type of being the principal.
Explore related questions
See similar questions with these tags.