4

so my domain model has a property named Children which returns all menus with the ID of the current object. I want to create a view model and in controller map the values between them. So Children property is IEnumerable<MenuModel> and menu.Children is of type IEnumerable<MenuCache>. What would be the easiest way to do it? Do I need to spin through all children and add them manually to current model and just repeat that for all levels?

Model:

public class MenuModel
{
    public int ID { get; set; }

    public string URL { get; set; }

    public int ParentID { get; set; }

    public IEnumerable<MenuModel> Children { get; set; }
}

Controller:

using (var context = ww.WebObjs.WebDataContext.Get())
{
    var menu = context.MenuCaches.Where(x=> x.ID == 0).FirstOrDefault();
    model = new MenuModel()
    {
        ID = menu.ID,
        URL = menu.Text,
        ParentID = menu.ParentID,
        Children = menu.Children // how do I get those children?
   };
}
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
bobek
  • 8,003
  • 8
  • 39
  • 75
  • 2
    Tip: `MenuCaches.FirstOrDefault(x => x.ID == 0)` is equivalent code. – Robert Harvey Aug 24 '12 at 19:52
  • Maybe this question should help http://stackoverflow.com/questions/4652457/asp-net-mvc-problem-with-editortemplate-for-icollectiont-mapped-to-enum – Jorge Aug 24 '12 at 20:02

1 Answers1

2

You could use LINQ:

using (var context = ww.WebObjs.WebDataContext.Get())
{
    var menu = context.MenuCaches.Where(x => x.ID == 0).FirstOrDefault();
    model = new MenuModel()
    {
        ID = menu.ID,
        URL = menu.Text,
        ParentID = menu.ParentID,
        Children = menu.Children.Select(x => new MenuModel
        {
            Prop1 = x.Prop1,
            Prop2 = x.Prop2,
            // and so on ...
        })
   };
}

or AutoMapper which I would strongly recommend. So after defining the corresponding mappings your controller action becomes far more readable:

using (var context = ww.WebObjs.WebDataContext.Get())
{
    var menu = context.MenuCaches.Where(x => x.ID == 0).FirstOrDefault();
    model = Mapper.Map<MenuCache, MenuModel>(menu);
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Sooo, if the children keeps digging down to 2 or 3 levels I just do add more Linq for each level? – bobek Aug 24 '12 at 20:00
  • 1
    Yeap, you keep digging down. Or you use AutoMapper as I recommended. – Darin Dimitrov Aug 24 '12 at 20:00
  • My application is pretty large now, and I use domain models as View Models. I also have huge memory leak and I have to recycle App pol every few minutes. Can this be the cause? You think that moving everything to have separate view models will help? Thank Darin – bobek Aug 24 '12 at 20:32
  • I very highly doubt that using view models could cause a memory leak. But who knows, it's code after all that we write and we all make mistakes. – Darin Dimitrov Aug 24 '12 at 20:34
  • How can you possibly have memory leaks working in managed environment? Automapper is the way to go - does all the work for you in significantly less code (read - less bugs:) ) – Display Name Aug 24 '12 at 22:01
  • @DisplayName, what percentage do you think of the code you write in C# is pure managed? You will be surprised, but most of .NET BCL class methods end up calling Win32 functions. You know, things like opening file handles, databases connections, network I/O, and I don't even wanna mention things like image manipulation with GDI+, ... All this is very, very unmanaged code. So for example fail to wrap an `IDisposable` object dealing with unmanaged resources and handles in a `using` statement and you will be leaking memory like hell. – Darin Dimitrov Aug 24 '12 at 22:04
  • Darin, this code (with all my menu levels) ends up being 225 queries to the database. How can I eager load the Children so that I only have one call to the database? – bobek Aug 28 '12 at 14:51
  • @bobek, that will depend on the database access technology that you are using. If you are using EF I think it supports eager loading through the Include extension method where you need to load the Children collection within the same query. – Darin Dimitrov Aug 28 '12 at 14:53
  • I am using linq to sql. It looks like eager loading isn't supported for cycling. I'll google, maybe I'll find something. Thanks! – bobek Aug 28 '12 at 14:58
  • Hi, I tried automapper but I think that for optimization it is not the best solution. It added plenty of queries that were not needed and when I do the mapping logic myself, it works much, much better. Thanks though! – bobek Oct 12 '12 at 16:08