2

I working in an ASP.NET MVC5 project and have a viewmodel class called PlacementStudentIndexData which has four collections of Ienumerables,

The viewmodel class is declared as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Placementv2.Models;
using IdentitySample.Models;
namespace Placementv2.ViewModels
{
    public class PlacementStudentIndexData
    {
        public IEnumerable<ApplicationUser> UserChoice1 { get; set; }
        public IEnumerable<ApplicationUser> UserChoice2 { get; set; }
        public IEnumerable<ApplicationUser> UserChoice3 { get; set; }
        public IEnumerable<Placement> Placement { get; set; }
        public double distance { get; set; }
    }

Note the ApplicationUser is uses the user objects on the objects in Identity2.0.

The Placements Controller has a Details Action to pass ViewModel data to a razor view built on this ViewModel which performs a matching exercise between the two objects and returns three matched collections of Users and an collection with a single instance of Placement type based on the int value passed to the Action to indicate which Placement object to return)

  public ActionResult Details(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var viewModel = new PlacementStudentIndexData();
        viewModel.Placement = db.Placements.Where(p => p.PlacementID== id.Value);
        viewModel.UserChoice1 = db.Users.Where(p => p.Choice1 == viewModel.Placement.FirstOrDefault().PlacementOrganisation.PlacementTypeID).Where(p => p.Placed == false);
        viewModel.UserChoice2 = db.Users.Where(p => p.Choice2 == viewModel.Placement.FirstOrDefault().PlacementOrganisation.PlacementTypeID).Where(p => p.Placed == false);
        viewModel.UserChoice3 = db.Users.Where(p => p.Choice3 == viewModel.Placement.FirstOrDefault().PlacementOrganisation.PlacementTypeID).Where(p => p.Placed == false);


        return View(viewModel);

Elsewhere in my Placement controller I have the following method and am looking for advice on how to update this distance into the individual user instances as calculated against the current placement instance. The calculation should be based on passing geocoordinates which are already stored in the database for the User object and the PlacementOrganisation (which is associated to the Placement)

 public double CalculateDistance(double startlat, double startlong, double endlat, double endlong)
            {
[Google MAPS API calculation and JSON deserialisation code here]
                return distancekms;    
            }

My difficulty is where in my code to perform these calculations and I'm looking for advice on how to update the distance attribute for the existing three UserChoice1,UserChoice2, UserChoice3 collections (As a side note, I know these are ienumerables, is it wrong to describe them as collections?)

If so could someone give me an example of how I would extend out my Details controller action to include a call to this CalculateDistance method so that the updated distance attribute for each User instance is part of the ViewModel passed to the Razor View.

Note- I've already tried include a foreach block in the controller method which called the CalculateDistance method along the following lines

foreach (var item in viewModel.UserChoice1)
            {
                viewModel.UserChoice1.First().distance = Calculatedistance(viewModel.Placement.First().PlacementOrganisation.Latitude, viewModel.Placement.First().PlacementOrganisation.Longtitude, viewModel.UserChoice1.First().Latitude, viewModel.UserChoice1.First().Longtitude);
            }

However, it's throwing the following exception: "There is already an open DataReader associated with this Command which must be closed first."

Please let me know if you can see a way to achieve what I'm trying to do here within the Details action of my Placement controller. Alternatively, should I be looking to call this CalculateDistance method from the view as I iterate through the User objects, or performing the calculation via Javascript in the View itself.

Thanks in advance for any help/advice you can offer on this.

John O'Grady
  • 235
  • 3
  • 14
  • 1
    thank you @CodeCaster. New to StackOverflow so was unclear how much background info was relevant. Have had a few negative experiences on here where I got replies which went off on a irrelevant tangents so was trying to be specific about my scenario but obviously went overboard. Now edited back as per your suggestion to focus on the kernel of the query – John O'Grady Sep 13 '15 at 12:38
  • 1
    @JohnO'Grady [Read this](http://stackoverflow.com/questions/6062192/there-is-already-an-open-datareader-associated-with-this-command-which-must-be-c) – Dandy Sep 13 '15 at 12:43
  • Thanks @Dandy. MARS is already set to true in the connection string in my webconfig file – John O'Grady Sep 13 '15 at 12:45

1 Answers1

0

The Link that @Dandy provided did contain the solution in one of the lower voted answers on that link.

The solution is to append .ToList() to the Ienumerables and that seems to close the DataReader properly.

This eventually got me past the issue where my foreach loop was throwing an error

public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var viewModel = new PlacementStudentIndexData();
            viewModel.Placement = db.Placements.Where(p => p.PlacementID == id.Value).ToList();
            viewModel.User = db.Users.Where(p => p.Placed == false).OrderBy(p=>p.distance).ToList();


            foreach (ApplicationUser user in viewModel.User)
            {
               user.distance = Calculatedistance(user.Latitude,user.Longtitude, viewModel.Placement.FirstOrDefault().PlacementOrganisation.Latitude, viewModel.Placement.FirstOrDefault().PlacementOrganisation.Longtitude);

            }
              return View(viewModel);

        }
John O'Grady
  • 235
  • 3
  • 14