Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

MVC question, 2 models in 1 view...

Options
2»

Comments

  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    Had to build it one last time bfore I left work, no errors now and no data type mismatches or errors of that type, but the page is blank where I expected to see data as per my select query parameter in my controller. Will have a look at it later!


  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    Ok back at this this morning, last night I found that my model is null, there is no data in it?!? I put a breakpoint into my code at return View(model); and I can look in there and view the query but there is no data in there. I've no errors on build or no errors preventing the view from rendering but there is no data in my model as expected.

    Strangely, I have a similar view in my solution that accesses the data using just a single model, not the MergedModel that has been the subject of this thread, and the controller code is pretty much identical, this was covered in this thead: http://www.boards.ie/vbulletin/showt...p?t=2057380052

    And in that view, there are several rows of data being returned when I use that view.

    I've posted my controller code again for my MyMergedModel approach below:
                    string QueryStatus = "Query";
                    string StockID = "ProductID1";
                    var context = new MyMergedModelDBContext();
                    var vehicles = context.VehicleDBs.Where(v => v.Status == QueryStatus).AsEnumerable<Vehicle>();
                    var products = context.ProductDBs.Where(p => p.StockID == StockID).AsEnumerable<Product>();
    
                    MyMergedModel model = new MyMergedModel
                    {
    
                        Vehicles = vehicles,
                        Products = products
    
                    };
    
                    return View(model);
    

    My code for the single model which is returning the data I need is below:
                    string QueryStatus = "Query";
    
                    var context = new VehicleDBContext(); 
    
                    var query = context.VehicleDBs.Where(p => p.Status == QueryStatus);
    
                    if (!string.IsNullOrEmpty(QueryStatus))
                    {
                        //query = query.Where(p => p.Status == QueryStatus);
                        query = query.OrderByDescending(p => p.ID);
                    }
    
                    var results = query.ToList(); //this executes your query and retrieves the results into memory
    
                    return View(results);
                }
    


  • Registered Users Posts: 403 ✭✭counterpointaud


    The difference is you are calling ToList() on the controller that is working.

    I think you are coming up against EF lazy-loading. The collection not built until it is needed. It thought that iterating over it would build it, but probably not if you are only iterating in the view. Try replacing the calls to AsEnumerable() with ToList().


  • Registered Users Posts: 11,977 ✭✭✭✭Giblet


    You shouldn't pass any domain models to the view at all, Vehicles and Products need to have view models also.


  • Registered Users Posts: 403 ✭✭counterpointaud


    Giblet wrote: »
    You shouldn't pass any domain models to the view at all, Vehicles and Products need to have view models also.

    Might be good practice generally, but they don't need to have view models.


  • Advertisement
  • Registered Users Posts: 11,977 ✭✭✭✭Giblet


    Might be good practice generally, but they don't need to have view models.

    Well you could get away with it, but you shouldn't really, the DBContext should be disposed by this point using an ActionFilter or similar or else you will expose it to view logic which is a bad bad idea.


  • Registered Users Posts: 403 ✭✭counterpointaud


    Giblet wrote: »
    Well you could get away with it, but you shouldn't really, the DBContext should be disposed by this point using an ActionFilter or similar or else you will expose it to view logic which is a bad bad idea.

    OK now I'm intrigued... how is DbContext exposed to the view ? Assuming your DbContext class is not contained in your domain model, which it shouldn't be anyway.


  • Registered Users Posts: 11,977 ✭✭✭✭Giblet


    OK now I'm intrigued... how is DbContext exposed to the view ? Assuming your DbContext class is not contained in your domain model, which it shouldn't be anyway.

    EF uses dynamic proxying to do lazy loading, the properties to be lazy loaded are virtual and overridden by EF to add the call to the database (so effectively, your model is using the context). If your context is disposed, this won't work (as of course, lazy loading requires the context) Really it should be disposed at this point anyway. A unit of work should be as tight as possible, and handled by the framework. Having a primed lazy loaded property in the view leaves you vulnerable to select n+1 and horrible joins.


  • Registered Users Posts: 403 ✭✭counterpointaud


    Interesting, thanks. Sorry to go a little off-topic OP, although this is somewhat relevant. I had always kind of assumed the DbContext instantiated in the controller would be disposed when the method returned.


  • Registered Users Posts: 11,977 ✭✭✭✭Giblet


    Interesting, thanks. Sorry to go a little off-topic OP, although this is somewhat relevant. I had always kind of assumed the DbContext instantiated in the controller would be disposed when the method returned.

    If you use a using declaration, it would be. Otherwise it would wait until the object was finalised (if you have overridden it to call dispose, or else it will never be called), which is done after garbage collection has occurred and is non deterministic.


  • Advertisement
  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    The difference is you are calling ToList() on the controller that is working.

    I think you are coming up against EF lazy-loading. The collection not built until it is needed. It thought that iterating over it would build it, but probably not if you are only iterating in the view. Try replacing the calls to AsEnumerable() with ToList().

    I've tried this advice but am still getting no data. I've put a breakpoint into my controller method at:

    return View(model);

    and when it breaks when I load the page, I can hover my mouse over the above line of code when it is still running in Visual Studio 2012, to see what is going on there and I can click down into what is in my model and it says

    Products: Count = 0
    Vehicles: Count = 0

    :confused::confused::confused:

    EDIT: I've also changed my controller code to:
    var vehicles = context.VehicleDBs.Where(v => v.Status == QueryStatus).ToList<Vehicle>();
    
    var products = context.ProductDBs.Where(p => p.StockID == StockID).ToList<Product>();
    


  • Registered Users Posts: 403 ✭✭counterpointaud


    So I guess your .Where() filter is not returning any records. Maybe try with it removed ? i.e. context.VehicleDBs.ToList()


  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    So I guess your .Where() filter is not returning any records. Maybe try with it removed ? i.e. context.VehicleDBs.ToList()

    Just tried that, still no result...


  • Registered Users Posts: 403 ✭✭counterpointaud


    Just tried that, still no result...

    Please ensure that there is data in your db tables, and that you are connecting to the correct db. If these look ok, post your DbContext code again.


  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    Please ensure that there is data in your db tables, and that you are connecting to the correct db. If these look ok, post your DbContext code again.

    There is defo data in my table because my other view with the controller data I posted earlier (which is very similar to my the controller code for the current issue), is returning several rows of data as expected.

    This is my DBContext Code that is in my MergedModel
    namespace MyMVCSolution.Models
    {
    
        public class MyMergedModel
        {
    
            public IEnumerable<MyMVCSolution.Models.Vehicle> Vehicles { get; set; }
            public IEnumerable<MyMVCSolution.Models.Product> Products { get; set; }
    
        }
    
        public class MyMergedModelDBContext : DbContext
        {
    
            public DbSet<MyMVCSolution.Models.Vehicle> VehicleDBs { get; set; }
            public DbSet<MyMVCSolution.Models.Product> ProductDBs { get; set; }
    
        }
    
    
    }
    

    This is my model for the single view that IS successfully returning the data from my DB...
    namespace MyMVCSSolution.Models
    {
        public class Vehicle
        {
    
            public Int32 ID { get; set; }
    
            public string VehicleID { get; set; }
    
            public DateTime Timestamp { get; set; }
    
            public string VehicleMake { get; set; }
    
            public string VehicleModel { get; set; }
    
            public string Owner { get; set; }
    
            public string Status { get; set; }
    
        }
    
        public class VehicleDBContext : DbContext
        {
            public DbSet<Vehicle> VehicleDBs { get; set; }
    
        }
    

    The code extract above is in a file in my "Models" folder named Vehicle.cs


  • Registered Users Posts: 403 ✭✭counterpointaud


    Are these both two different projects? Please compare connection strings etc. and make sure you are connecting to the same db in both cases?


  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    Are these both two different projects? Please compare connection strings etc. and make sure you are connecting to the same db in both cases?

    Yup they are both in the same project/solution, the connection string is in the web.config file, I'm assuming that because it is connecting to the DB for my 'Vehicle.cs' model and bringing back & displaying rows of data, that it is good.

    Here is the view that is working & displaying data:
    @model IEnumerable<MyMVCSolution.Models.Vehicle>
    
    @{
        ViewBag.Title = "View My Queries";
        Layout = "~/Views/Shared/_Layout.MobileThemeroller.cshtml";
    }
    
    @using (Html.BeginForm("ViewMyQueries", "Home", FormMethod.Post)) 
    {
    <div ID="MyCollapsibleSet" data-role="collapsible-set" style="box-shadow:none;" data-iconshadow="false">
    @foreach (var item in Model) {
         
      
    <div data-role="collapsible" data-theme="d" data-content-theme="d" data-iconshadow="false" data-collapsed="true" data-mini="true" data-collapsed-icon="arrow-r" data-expanded-icon="arrow-d">  
        <h3>@Html.DisplayFor(modelItem => item.VehicleID)</h3/></div>@Html.DisplayFor(modelItem => item.VehicleMake) @Html.DisplayFor(modelItem => item.VehicleModel)
    

    This works fine, no problem returning data from DB, when I try to do it using a new model containing models 'Vehicle' and 'Product', no data?!?

    I'm obviously new at this but I can't figure out wtf I'm doing wrong here!

    I do want to access data from 2 completely separate tables though from the same view so I'm stuck with this, as I've learnt that I can't declare 2 separate models at the top of the same view unfortunately...


  • Registered Users Posts: 403 ✭✭counterpointaud


    Can't see what is happening. Confirm that product and vehicle are empty lists (count == 0) for both queries. It seems that EF is successfully querying some db for you and returning 0 rows.

    My advice would be to create a new file for your DbContext, and put all model classes in there, stop creating more than one DbContext, and try again. You can just copy paste your VehicleDbContext class to a new file and add a DbSet for product. Delete the MergedModelDbContext, you don't need it.


  • Closed Accounts Posts: 1,143 ✭✭✭LordNorbury


    Can't see what is happening. Confirm that product and vehicle are empty lists (count == 0) for both queries. It seems that EF is successfully querying some db for you and returning 0 rows.

    My advice would be to create a new file for your DbContext, and put all model classes in there, stop creating more than one DbContext, and try again. You can just copy paste your VehicleDbContext class to a new file and add a DbSet for product. Delete the MergedModelDbContext, you don't need it.

    Huge thanks, this has sorted the problem, something with the DBContext in my new model (MergedModelDBContext), isn't workingcorrectly, I've resolved it using the DBContext in each individual model even though both models 'Vehicle' and 'Product' are still being called up via my new Mergedmodel which contains 'Vehicle' and 'Product'
                    var VehicleContext = new VehicleDBContext();
                    var ProductContext = new ProductDBContext();
                    var vehicles = VehicleContext.VehicleDBs.ToList<Vehicle>();
                    var products = ProductContext.ProductDBs.ToList<Product>();
    
                    MyMergedModel model = new MyMergedModel
                    {
    
                        Vehicles = vehicles,
                        Products = products
    
                    };
    
                  
                    return View(model);
    

    I wanted to use a single DB context to access both 'Vehicle' and 'Product' as I would have thought that this was better practice, given that my two models were now being accessed from a new model that merged both 'Vehicle' and 'Product' models. But at the same time I need a result so maybe this is what I'll have to use for the mo.

    Obviously my experience here is very weak, hence why I'm trying to understand new techniques and learn best practice, rather than having to fall back on a previous technique that I used, just to get a result on the day.

    Huge thanks again to folks on thread for helping me out of yet another MVC/EF cul de sac I have found myself stuck in!


Advertisement