0

I'm fairly new to MVC and I've been trying to create a view using a DTO as the Model Class, but it seems to be using the Data Context class I use for my Models, even though I am clearing the selection when I am creating the view.

This issue seems to be causing a NullReferenceException which is caused by the following exception being thrown and the view not having any returned to it.

ITSSkillsDatabase.Models.PersonSkillSetsDTO: : EntityType 'PersonSkillSetsDTO' has no key defined. Define the key for this EntityType.

PersonSkillSets: EntityType: EntitySet 'PersonSkillSets' is based on type 'PersonSkillSetsDTO' that has no keys defined.

My DTO:

namespace ITSSkillsDatabase.Models
{
    public class PersonSkillSetsDTO
    {
        public int IDSkillset { get; set; }
        public int IDCategory { get; set; }
        public string Product { get; set; }
        public string P_Version { get; set; }
        public string Notes { get; set; }
        public int PersonSkillsID { get; set; }
        public int IDPerson { get; set; }
        public int Score { get; set; }
        public DateTime ScoreDate { get; set; }
        public int TargetScore { get; set; }
        public DateTime TargetDate { get; set; }
        public DateTime RefresherDate { get; set; }
    }
}

Controller method:

public ActionResult SkillSets(int? id)
{
    try
    {
        if (id == null)
        {
            return HttpNotFound();
        }
        var viewModel = (from a in db.SkillSets
                         join c in db.PersonSkills on a.IDSkillset equals c.IDSkillSet
                         where c.IDPerson == id
                         select new Models.PersonSkillSetsDTO
                         {
                             IDSkillset = a.IDSkillset,
                             IDCategory = a.IDCategory,
                             Product = a.Product,
                             P_Version = a.P_Version,
                             Notes = a.Notes,
                             PersonSkillsID = c.PersonSkillsID,
                             IDPerson = c.IDPerson,
                             Score = c.Score,
                             ScoreDate = c.ScoreDate,
                             TargetScore = c.TargetScore,
                             TargetDate = c.TargetDate,
                             RefresherDate = c.RefresherDate
                         }).ToList();
        return View(viewModel);
    }
    catch
    {
        return View(); //this is where the NullReferenceException is thrown
    }
}

These are the settings when I'm creating the view:

I realise I can get rid of the NullReferenceException by checking for null values, but I don't have any idea how to fix the issue with my DTO.

2
  • DTO is not part of your data Context that is why, You have to handle the context for DTOs/ ViewModels yourself. Commented Sep 14, 2015 at 12:23
  • @DawoodAwan I thought that might be the issue. I'm not really sure how to go about creating a context class for a DTO though. I have "public partial class LocalModel : DbContext" on my current context class, what would replace "DbContext" within that? (sorry for my lack of technical speech). Commented Sep 14, 2015 at 12:29

4 Answers 4

4

I am going to try to explain using a ViewModel/DTO to create a Form and POST back.

ViewModels are outside of the Database Context, So if you are using a ViewModel you have to Map your data from ViewModel to Model and Model to ViewModel.

So if you are reading from Database

  1. Create DBContext
  2. read data you want to read
  3. Map to a ViewModel
  4. Pass ViewModel to the View or API

If you are writing to the database

  1. POST ViewMdoel from View to Controller (You can use Ajax)
  2. Create DBContext
  3. Map from ViewModel to Model
  4. Save Model to Database

let's say you have a DTO,

   public class CountryDTO
    {

        public int CountryId { get; set; }

        [Display(Name = "Country Name")]
        [Required(ErrorMessage = "This field is required")]
        public string CountryName { get; set; }

        [Display(Name = "Latitude")]
        [Required(ErrorMessage = "This field is required")]
        public double CentralLat { get; set; }

        [Display(Name = "Longitude")]
        [Required(ErrorMessage = "This field is required")]
        public double CentralLang { get; set; }

        [Display(Name = "GMT Offset")]
        [Required(ErrorMessage = "This field is required")]
        public double GMTOffSet { get; set; }

        [Display(Name = "Currency")]
        [Required(ErrorMessage = "This field is required")]
        public string Currency { get; set; }
    }

Create a controller i.e. CountryController and you have a Views Folder Country, Right Click Country Folder Add --> View, Name it CreateCountry and Select Model to be CountryDTO

You can't select DataContext here , because DTO is not part of the Context

enter image description here

This will create your view with Fields from the DTO.

Now in your Controller you need 2 Actions

  1. GET method to return the View
  2. POST method to POST back the form

    public ActionResult CreateCountry()
    {
        return PartialView(new CountryDTO());
    }
    

Now in the POST method you will Pass the DTO, Let's assume you have a Country table in your Database, you will have to create a New Country type Object and add to the Context

    [HttpPost]
    public ActionResult CreateCountry(CountryDTO model)
    {
        if (ModelState.IsValid)
        {
            // Model State is Valid
            // here you will create Context

            using (var dbContext = new DATBASE_CONTEXT())
            {
                var newCountry = new Country() // Country is a Model from Database
                {
                    CountryName = model.CountryName,
                    CentralLat = model.CentralLat,
                    // Map All Properties from View Model to Model
                };

                // Add the New Country to the Countries 
                dbContext.Countries.Add(newCountry);

                // Save Database Changes
                dbContext.SaveChanges();
            }
        }
        return PartialView(model);
    }

enter image description here

IF you want to display this Country:

    public ActionResult CountryDetails(int id)
    {
        var model = new CountryDTO();

        using (var dbContext = new DATABASE_CONTEXT())
        {
            var country = dbContext.Country.First(s => s.CountryId == id);
            model.CountryName = country.CountryName;
            // Same for other Properties
            // You can use AutoMapper Library to Map from Model to DTO/ViewModel

        }
        return View(model);
    }
Sign up to request clarification or add additional context in comments.

7 Comments

I am able to select a context, but I don't want to, but it still uses the same Context as my Models even when I clear the selection.
You have to create a Context in Controller or your Data Layer -- using (var dbContext = new DATABASE_CONTEXT())
I don't understand why the DTO would need to be part of the DbContext, because the data it is storing is not coming from the database, it isn't coming from two models within the application.
It is not part of the DbContext. But to read data from the database you have to read data from dbContext.Countries to CountryDTO to display data
So if I add it into my context class like so, it should work? i.imgur.com/RLGFRcB.png
|
0
try
{
    // <...>
    return View(viewModel);
}
catch
{
    return View(); //this is where the NullReferenceException is thrown
}

You get NullReferenceException because your view expects the model and doesn't perform null checks in Razor.

To verify this, you can create a dummy model and pass it into your return View(/* model */); call.

1 Comment

I know that much, the real issue is concerning the DTO
0

As I understood the exception trouble is not with DbContext but with lame model: "No key defined". I think checking data-annotations might help.

1 Comment

It shouldn't be using the DbContext, as the DTO is receiving it's data from two of the models already present.
-1

I created a new View Model which contains everything I need from the two models.

I then set the values for the View Model within the controller.

Which gave me the result I wanted. enter image description here

Comments

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.