Recently we started a new (API) project in .NET CORE 2 which has some endpoints in the API project and the database (POCO) models (EF CORE) in a separate DAL project.
With the use of Entity Framework Core and FluentAPI we are building the database code-first.
Some proof-of-concept Endpoints and Tables (also with many-to-many relationships) are created in both projects. This all seems to be working fine.
The problem we are facing now however is the fact that some POCO classes have relationships to other tables / POCO classes, see the below example:
public class Medium
{
public Medium()
{
this.Hold = new HashSet<Hold>();
this.InExMedium = new HashSet<InExMedium>();
}
public long MediumID { get; set; }
public long SolutionID { get; set; }
public string Name { get; set; }
public Solution Solution { get; set; }
public ICollection<Hold> Hold { get; set; }
public ICollection<InExMedium> InExMedium { get; set; }
}
In our Medium endpoint we don't want the Hold
and InExMedium
properties to be visible or evaluated in the ModelState.IsValid
function.
Our first solution was to make these properties internal
instead of public
, which worked in the beginning. However, we soon realized that this is not the proper way since other functions could not longer be properly used (like LINQ).
The solution, at least I think, is to use a layer in between, ViewModels
.
For the above problem I created the following (test) ViewModel
:
public class MediumViewModel
{
public Medium Medium { get; set; }
public InExMedium InExMedium { get; set; }
public Solution Solution { get; set; }
public Hold Hold { get; set; }
}
I know this ViewModel
is the same as the original POCO class but I just want to test it with some LINQ in the Endpoint's Controller.
However, I immediately stumble upon several issues. For example, all the POCO classes are added to our DBContext
class, but how can I link the ViewModel
to it ass well? Is this even needed?
When I try to Scafold an API Controller with the just created ViewModel as Model and our DbContext as Data context class, I am getting the following error:
There was an error running the selected code generation: 'Could not add Model type MyProject.API.Viewmodels.MediumViewModel' to DbContext 'MyProject.MyDbContextClass'. Please make sure that 'MyProject.MyDbContextClass' has a DbSet property for 'MyProject.API.Viewmodels.MediumViewModel'
What is the best way to handle this? I've read some things about AutoMapper
but i prefer to not use another library to achieve this.
In the API controller I am using the DbContext like so:
public class MediaController : TrsBaseController
{
public MediaController(MyDbContext context)
: base(context)
{
}
//// GET: api/media
[HttpGet]
public async Task<IEnumerable<Medium>> GetMedia()
{
return await this.Context.Medium.ToListAsync();
}
}
When using a ViewModel
, can I still use the DbContext
as above or should I implement it differently?
I've looked around to find good tutorials about this issue but I guess I am googling on the wrong keywords since I can't find a lot of tutorials (which are also up to date with .NET CORE 2).
Does this work for you? I changed the MediumViewModel to use as example. You can make it async!
public class MediaController : TrsBaseController
{
public MediaController(MyDbContext context)
: base(context)
{
}
//// GET: api/media
[HttpGet]
public IEnumerable<MediumViewModel> GetMedia()
{
var result = this.Context.Medium.ToList();
return result.Select(x=> new MediumViewModel {Medium = x.MediumID, Solution = x.SolutionID}); // and so on
}
}
public class MediumViewModel
{
public long Medium { get; set; }
public long Solution { get; set; }
}