Stian
Stian

Reputation: 1602

Why can't I get this model to map to this viewmodel?

I have this entity model for a recursively structured category tree:

public class ProductCategory
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Title { get; set; }
    public int SortOrder { get; set; }

    public ProductCategory ParentCategory { get; set; } //nav.prop to parent
    public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
    public ICollection<ProductInCategory> ProductInCategory { get; set; }
    public ICollection<FrontPageProduct> FrontPageProduct { get; set; } // Nav.prop. to front page product

    // Recursive sorting:
    public void RecursiveOrder()
    {
        Children = Children.OrderBy(o => o.SortOrder).ToList();
        Children.ToList().ForEach(r => r.RecursiveOrder());
    }
}

... and this, supposedly, matching ViewModel:

public class ViewModelProductCategory
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Title { get; set; }
    public int SortOrder { get; set; }
    public bool Checked { get; set; } // Used for assigning a product to multiple categories in Product/Edit

    // Nav.props:
    public ViewModelProductCategory ParentCategory { get; set; } // Nav.prop. to parent
    public ICollection<ViewModelProductCategory> Children { get; set; } // Nav.prop. to children
    public IEnumerable<ViewModelProduct> Products { get; set; } // Products in this category
    public IEnumerable<ViewModelFrontPageProduct> FrontPageProducts { get; set; }

    public string ProductCountInfo { get { return Products?.Count().ToString() ?? "0"; } }
}

When I try to populate the viewmodel, like this:

List<ProductCategory> DbM = 
    await _context.ProductCategories
        .Include(c => c.Children)
        .Where(x => x.ParentId == null)
        .OrderBy(o => o.SortOrder)
        .ToListAsync();
foreach (var item in DbM)
{
    VMSelectCategories.Add(
        new ViewModelProductCategory{
            Id = item.Id,
            Children = item.Children,
            Title = item.Title
        });
}

VisualStudio screams at me that it can't implicitly convert ProductCategory to ViewModelCategory. This happens at Children = item.Children.

Why isn't it working? Can't I have additional properties in the viewmodel that I use unrelated to the original entity model? Like Checked and ProductCountInfo?

Upvotes: 1

Views: 50

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54427

In this line:

Children = item.Children,

Children is the ViewModelProductCategory.Children property, which is type ICollection<ViewModelProductCategory>, while item.Children is the ProductCategory.Children property, which is type ICollection<ProductCategory>. They are different types and neither inherits or implements the other so why would you expect to be able to assign an object of one type to a property of the other type? Would you expect this to work:

var list1 = new List<int> {1, 2, 3};
List<string> list2 = list1;

Of course not (I hope) because assigning a List<int> object to a List<string> variable would be silly. What you're trying to do is exactly the same. You need to provide some way to convert from one type to the other and then implement that in your code. An option for that might be like this:

Children = item.Children.Select(pc => MapToViewModel(pc)).ToList(),

where MapToViewModel is a method that you write to create a ViewModelProductCategory and populate its properties from a ProductCategory parameter.

You might also look at using something like AutoMapper.

Upvotes: 1

Related Questions