0

I'm attempting to return a custom view model from an ODataController. Here is the view model:

public class TaskViewModel
{
    public int TaskID { get; set; }
    public string Name { get; set;}
    public string Details { get; set; }
    public DateTime? DueDate { get; set; }
    public virtual Project Project { get; set; }
}

My controller looks like this:

public IEnumerable<TaskViewModel> Get(ODataQueryOptions<TaskViewModel> options)
{
    IEnumerable<Task> tasks = db.Tasks.AsEnumerable();
    ...
    var vm = from t in tasks
             select new TaskViewModel
             {
                 TaskID = t.TaskID,
                 Name = t.Name,
                 Details = t.Details,
                 DueDate = t.DueDate,
                 Project = t.Project
             }
    return vm.AsEnumerable();
}

The Task entity looks like this (generated from database-first EDMX):

public partial class Task
{
    public int TaskID { get; set; }
    public string Name { get; set; }
    public string Details { get; set; }
    public DateTime? DueDate { get; set; }
    ... //other properties I don't want exposed
    public virtual Project Project { get; set; }
}

When I attempt to perform a GET, I receive the following message:

"No NavigationLink factory was found for the navigation property 'Project' from entity type 'MyApplication.ViewModels.TaskViewModel' on entity set 'Tasks'. Try calling HasNavigationPropertyLink on the EntitySetConfiguration."

Here is my WebApiConfig.cs:

builder.EntitySet<Project>("Projects").EntityType.HasKey(p => p.ProjectID);
builder.EntitySet<Task>("Tasks").EntityType.HasKey(t => t.TaskID);
...
builder.EntitySet<ViewModels.TaskViewModel>("TaskViewModel");

I've successfully done this with another entity in the application (Project), so I don't know why this one isn't working. The only difference is the Task entity references the Project entity.

Any help/insight is appreciated.

user1147941
  • 121
  • 2
  • 16
  • Are you having any table called `TaskViewModel` in your database? – Jenish Rabadiya Sep 29 '15 at 16:35
  • No, it's not part of the database. However, I was able to successfully use a ProjectViewModel class w/o adding it to the database. – user1147941 Sep 29 '15 at 16:36
  • Then why have you applied line `builder.EntitySet("TaskViewModel");` to your configuration? – Jenish Rabadiya Sep 29 '15 at 16:37
  • Everything I had read stated that had to be in there. If I take it out, I receive the error: "The given model does not contain the type 'MyApplication.ViewModels.TaskViewModel'. – user1147941 Sep 29 '15 at 17:52
  • See https://stackoverflow.com/questions/15008450/using-ef-and-webapi-how-can-i-return-a-viewmodel-and-support-iqueryable-odata – romanoza Jun 27 '17 at 14:13

1 Answers1

1

I was able to get it working. All I did was make the TaskViewModel class a derived class of Task.

From:

public class TaskViewModel
{
    public int TaskID { get; set; }
    ...
    public string CurrentStatus { get; set; }
}

To:

public class TaskViewModel : Task
{
    public string CurrentStatus { get; set; }
}

It's also worth noting that this worked with or without the entry for TaskViewModel in WebApiConfig.cs.

user1147941
  • 121
  • 2
  • 16
  • 6
    Having your DTO derive from your domain model is far from ideal – Cocowalla Jul 06 '16 at 11:11
  • sorry to necro up this thread but has anyone found a more optimal solution that is just as succinct? – notsoobvious Jun 06 '17 at 05:45
  • @Cocowalla why you said that? – X.Otano Jul 19 '18 at 09:43
  • 3
    @Badulake because one of the main reasons for DTOs is that views often need different data than the domain model provides, or need it in a flattened, formatted, parsed, or otherwise differing format – Cocowalla Jul 19 '18 at 15:13
  • @Cocowalla ,sometimes could happen that you need just a few more fields that the Domain model class, how do you handle that? – X.Otano Jul 19 '18 at 15:14
  • 2
    @Badulake I'd still use a DTO that doesn't inherit from my domain model, and I'd use AutoMapper or similar to do the monkey-work of mapping properties to the DTO for me – Cocowalla Jul 20 '18 at 08:24