Testing results with Massive - massive

I'm returning a list to my MVC controller from Massive. When I'm in my test how can I check that there are 3 records (as expected) in the returned list?
My test code currently returns the 3 records from a call and populates into my ViewModel (model) but when I try to run .Count() it's saying object has no Count method. Since it's a dynamic type what do I do?
My test code:
var result = _controller.Index() as ViewResult;
var model = result.Model as MyExperienceListModel;
Assert.AreEqual(3, model.Experience.Count());
model.Experience is dynamic btw.

I got this working by having my returned result set from my Massive class as a IEnumerable<dynamic> in my ViewModel. So:
MyExperienceListModel{
public IEnumerable<dynamic> Experience { get; set;}
}
Hope it helps someone else out.

Related

Display error even while Model.IsValid returns true

I'm making a website that pulls some information from a SQL DB.
I have made a Model for validating that i have the information i need before i try the query. This means (if things go right) the method will always resolve and the Model.IsValid will be true. The query is to get all rows between two given dates.
Now comes my problem - When it gets into the ActionResult where it calls the query i first want to check if the amount of rows returned is less than 1000.
If it is < 1000 i want it to show the view with the rows, however if it's greater than 1000 i want an error message to be displayed that tells the user to narrow the search criterias.
I might be going about this the complete wrong way, and my initial idea was to "simply" change the validator to no longer being valid. Which would the automatically trigger the error message from the model. After searching around though that doesn't seem to be a possibility.
Anyone got some ideas how to go about this? Am completely wrong about my approach?
ValidatorModel:
public class DateValidator
{
[Required]
public DateTime StartDateTime { get; set; }
[Required]
public DateTime EndDateTime { get; set; }
}
ActionResult:
public ActionResult GetListFromDateRange(DateValidator validator)
{
RangeParent parent = new RangeParent();
if (ModelState.IsValid)
{
int queryCount =
repository.GetCountFromDateRange(validator.StartDateTime,
validator.EndDateTime);
if (queryCount < 1000)
{
parent.Meters =
repository.GetListFromDateRange(validator.StartDateTime,
validator.EndDateTime);
return View(Constants.ViewNames.DisplayRangeData, parent);
}
else
{
//display error message telling user to narrow the datetime range
return new EmptyResult();
}
}
return View(Constants.ViewNames.IndexView);
}
And last the two queries i currently use:
public List<Meter> GetListFromDateRange(DateTime startDateTime, DateTime endDateTime)
{
using (dbContext = new HeatDataVerifEntities())
{
return dbContext.Meters.Where(p => p.Created >= startDateTime && p.Created <= endDateTime).OrderBy(p => p.Created).ToList();
}
}
public int GetCountFromDateRange(DateTime startDateTime, DateTime endDateTime)
{
using (dbContext = new HeatDataVerifEntities())
{
return dbContext.Meters.Where(p => p.Created >= startDateTime && p.Created <= endDateTime).Count();
}
}
Another thing i considered was to create another ActionResult that runs the check for the row size which i would call instead of 'GetListFromDateRange' - and then have that either return an empty partial view along with calling the method for getting the list of item, or returning a partial view that has an error message in it. It just seemed like the should/could be an easier or smarter solution to that.
Again i have been searching around, but as i also mentioned i might simply just be looking at this wrong.
Thanks in advance.
Displaying around 1000 records on one page is not exactly useful, plus it affects many things, such as the performance of your database, depending on how many users request data at the same time, how fast the website displays the data to the users and ultimately your website might crash completely if too many sets of data are requested at the same time.
Instead, why don't you simply add pagination? Decide on a page size, say 20, return those records from your query, together with the number of pages required to display all data. You can then use that to build the page pagination itself. So you never return more than 20 rows from your db, the pressure is minimal, the site runs quickly.
The way you are going now, you are requesting a lot of data, and if you have more than 1000 records all you do is display an error message expecting the user to make another request. You already have the data though, but you're not using it for anything other than a count. Unless a course, all you do is run a count first and then if less than 1000 then you run the actual query.
Model validation is run on inputs, not outputs and I wouldn't suggest you try to change the way MVC works, just to fit a specific scenario which shouldn't happen anyway.
If you want to crack on with your idea then run the count query first, if result is over 1000 then return an error message and display that to the user. You can do this without any kind of custom, non-model validation.
You can always add a custom error message that will show up in ValidationSummary
ModelState.AddModelError(string.Empty, "My own error message");

Loading multiple sets of data in a content page in ASP.NET MVC Entitiy Framework

I need to load multiple entity types in my View page. I am using ViewModel for this purpose. However, I need to make around 5-6 database calls to load each set of data and assign them to the relevant property of the ViewModel. I wonder if this is a recommended approach since it requires multiple database calls. Or, am I being over-concerned about this? Here is a snapshot from my code:
var model = new EntryListVM();
string userid = "";
if (ViewBag.CurrentUserId == null)
userid = User.Identity.GetUserId();
else
userid = ViewBag.CurrentUserId;
ViewBag.CurrentUserId = userid;
//First database call
model.DiscussionWall = db.DiscussionWalls.Find(wallId);
//Second database call to learn if the current students has any entry
model.DiscussionWall.DoesStudentHasEntry = db.Entries.Any(ent => ent.DiscussionWallId == wallId && ent.UserId == userid);
model.PageIndex = pageIndex;
//Third database call
model.TeacherBadges = db.Badges.Where(b => b.CourseId == model.DiscussionWall.CourseId && b.IsSystemBadge == false && b.IsEnabled == true).ToList();
//Fourth database call
model.Reactions = db.Reactions.Where(re => re.CourseId == model.DiscussionWall.CourseId).ToList();
int entryPageSize = Convert.ToInt32(ConfigurationManager.AppSettings["EntryPageSize"]);
int firstChildSize = Convert.ToInt32(ConfigurationManager.AppSettings["FirstChildSize"]);
List<ViewEntryRecord> entryviews = new List<ViewEntryRecord>();
bool constrainedToGroup = false;
if (!User.IsInRole("Instructor") && model.DiscussionWall.ConstrainedToGroups)
{
constrainedToGroup = true;
}
//Fifth database call USING VIEWS
//I used views here because of paginating also to bring the first
//two descendants of every entry
entryviews = db.Database.SqlQuery<ViewEntryRecord>("DECLARE #return_value int;EXEC #return_value = [dbo].[FetchMainEntries] #PageIndex = {0}, #PageSize = {1}, #DiscussionWallId = {2}, #ChildSize={3}, #UserId={4}, #ConstrainedToGroup={5};SELECT 'Return Value' = #return_value;", pageIndex, entryPageSize, wallId, firstChildSize, userid, constrainedToGroup).ToList();
model.Entries = new List<Entry>();
//THIS FUNCTION MAP entryviews to POCO classes
model.Entries = ControllerUtility.ConvertQueryResultsToEntryList(entryviews);
//Sixth database call
var user = db.Users.Single(u => u.Id == userid);
model.User = user;
I wonder if this is too much of a burden for the initial page load?
I could use SQL-View to read all data at once, but I guess I would get a too complicated data set to manage.
Another option could be using Ajax to load the additional results after the page loading (with the main data) is completed. For example, I could load TeacherBadges with AJAX after the page is being loaded.
I wonder which strategy is more effective and recommended? Are there specific cases when a particular strategy could be more useful?
Thanks!
It all depends on your scenario - different scenarios have different ways of doing things. There is no single right way of doing things that are similar in nature. What might work for me might not work for you. Ever heard that saying: there are many ways to kill a cat? Well this certainly applies to programming.
I am going to answer based on what I think you are asking. Your questions are very broad and not that specific.
However, I am not sure if this is a recommended approach since it
requires multiple database calls.
Sometimes you need to do one database call to get data, and sometimes you need to do more than one database call to get the data. For example:
User details with addresses: one call for user and one call for addresses
User details: one call
I am using ViewModel for this purpose.
Using view models for your views is a good thing. If you want to read up more on what I had to say about view models then you can go and read an answer that I gave on the topic:
What is ViewModel in MVC?
View models are ideal for when you have data that is coming from multiple datasets. View models can also be used to display data coming from one dataset, for example:
Displaying user details with multiple addresses
Displaying only user details
I read the data in the controller in separate linq statements, and
assign them to the relevant List property of the ViewModel.
I would not always return a list - it all depends on what you need.
If I have a single object to return then I will populate a single object:
User user = userRepository.GetById(userId);
If I have a list of objects to return then I will return a list of objects:
List<User> users = userRepository.GetAll();
It is of no use to return a single object and then to populate a list for this object:
List<User> user = userRepository.GetByUserId(userId).ToList();
Second option could be using SQL-View to read all data with one
database call, and then map them to the entities properly in
controller.
This is similar to your first question, how you return your data on the database level is up to you. It can be stored procedures or views. I personally prefer stored procedures. I have never used views before. Irrespective of what you choose your above mentioned repository methods should still look the same.
Third option could be using Ajax to load the additional results after
the page loading (with the main data) is completed.
You can do this if you want to. I would not do it if it is not really needed. I try to load data on page load. I try to get as much data on the screen before the page is fully loaded. There have been times that I had to go the AJAX route after the page was loaded. After the page was loaded I had to do an AJAX call to load my HTML table.
If you really just need to have data displayed then do just that. You do not need any fancy ways of doing this. Maybe later you need to change on screen data, then AJAX is cool to use.
I wonder which strategy is more effective and recommended? Are there
specific cases when a particular strategy could be more useful?
Let us say you want to display a list of users. We do a database call and return the list to the view. I do not normally use view models if I only return a list:
public class UserController : Controller
{
private IUserRepository userRepository;
private IAddressRepository addressRepository;
public UserController(IUserRepository userRepository, IAddressRepository addressRepository)
{
this.userRepository = userRepository;
this.addressRepository = addressRepository;
}
public ActionResult Index()
{
List<User> users = userRepository.GetAll();
return View(users);
}
}
And your view could look like this:
#model List<YourProject.Models.User>
#if (Model.Count > 0)
{
foreach (var user in Model)
{
<div>#user.Name</div>
}
}
If you need to get a single user's details and a list of addresses, then I will make use of a view model because now I need to display data coming from multiple datasets. So a user view model can look something like this:
public class UserViewModel
{
public UserViewModel()
{
Addresses = new List<Address>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Address> Addresses { get; set; }
}
The your details action method could look like this:
public ActionResult Details(int id)
{
User user = userRepository.GetById(id);
UserViewModel model = new UserViewModel();
model.Name = user.Name;
model.Addresses = addressRepository.GetByUserId(id);
return View(model);
}
And then you need to display the user details and addresses in the view:
#model YourProject.ViewModels.UserViewModel
<div>First Name: #Model.Name</div>
<div>
#if (Model.Addresses.Count > 0)
{
foreach (var address in Model.Address)
{
<div>#address.Line1</div>
<div>#address.Line2</div>
<div>#address.Line3</div>
<div>#address.PostalCode</div>
}
}
</div>
I hope this helps. It might be to broad of an answer but it can guide you on the correct path.
Includes for linked data
For linked data it's simple (you probably know this way):
var users = context.Users.Include(user => user.Settings).ToList();
It queries all users and pre-loads Settings for each user.
Use anonymous class for different data sets
Here is an example:
context.Users.Select(user => new
{
User = user,
Settings = context.Settings
.Where(setting => setting.UserId == user.Id)
.ToList()
}).ToList();
You still kinda need to choose your main query collection (Users in this case), but it's an option. Hope it helps.

MVC3 unit testing

Im new to mvc 3 and I'm doing unit tests. I'm testing a search action method. This method returns an action method that contains a generic list of some type. How do I test if the model data returned is of that specified type?
Please help.
In your test method you do a type assertion after you have obtained the search results in a variable. Here is an assert for NUnit:
var searchResults = SearcherUnderTest.Search("TestKeyword");
Assert.IsInstanceOfType( Type expected, object searchResults );
Do you mean that you want to test the type of T in a List? If so then look at this question: How to get the type of T from a member of a generic class or method?
Or do you need help with writing a unit test for an action? Then: How to unit test an ActionResult that returns a ContentResult?
Testing with Nunit, it usually looks like this when testing search results:
[Test]
public void Search_ShouldReturnAListOfOrders()
{
var result = _controller.Search("searchParameter") as MyViewModel ;
Assert.That(result, Is.Not.Null);
Assert.That(result.SearchResults, Is.Not.Null);
Assert.That(result.SearchResults.Count, Is.GreaterThan(0));
}

Entity Framework error - nested model problem

I'm new to ASP.NET MVC and want to create a small order management tool. My database contains the tables Orders and Articles (and a few other ones), and I generated an EF Model from my database, so I can use the full power of the EF mappings (e.g. db.Orders.Articles)
My two main relations which I'm concerned about are Orders and Articles.
An order can have many articles
An article can only belong to one order.
I've created an OrdersController with an Create action to create an order:
//
// GET: /Orders/Create
public ActionResult Create()
{
Order order = new Order()
{
// filling some order columns, e.g. date
};
Article article = new Article()
{
// ... article columns
};
order.Articles.Add(article);
return View(order);
}
//
// POST: /Orders/Create
[HttpPost]
public ActionResult Create(Order order)
{
// i know i should care more about error handling, but now ommit it
db.Orders.AddObject(order);
db.SaveChanges();
return RedirectToAction("index");
}
So I'm directly binding an EF Object to a view (read somewhere not to do that and use a view model instead, but don't really know what that view model should look like)
My view contains the Order form as well as the article form (because i want to create a order and articles at the same time and not seperate). I used these greate EditorFor Methods to do that.
And now to my problem: If i hit the submit button, the app crashes as soon as it comes to the HttpPost Create Method (when mapping the order) with this error message:
Error Message: The EntityCollection
has already been initialized. The
InitializeRelatedCollection method
should only be called to initialize a
new EntityCollection during
deserialization of an object graph.
If i hit continue in VS2010, it will complete saving the order - so my question is how to solve this problem in a reliable way.
Thanks in advance and sorry for that long story :)
I solved my problem now by using a separate ViewModel like #Yakimych advised me. However I did not copy all the attributes from the EF models, instead I just refer to them. My ViewModel looks like this:
public class NewOrderViewModel {
public Order { get; set; }
public List<Article> { get; set; }
}

ASP.NET MVC: How to transfer more than one object to View method?

I finished NerdDinner tutorial and now I'm playing a bit with project.
Index page shows all upcoming dinners:
public ActionResult Index()
{
var dinners = dinnerRepository.FindUpComingDinners().ToList();
return View(dinners);
}
In DinnerRepository class I have method FindAllDinners and I would like to add to above Index method number of all dinners, something like this:
public ActionResult Index()
{
var dinners = dinnerRepository.FindUpComingDinners().ToList();
var numberOfAllDinners = dinnerRepository.FindAllDinners().Count();
return View(dinners, numberOfAllDinners);
}
Of course, this doesn't work. As I'm pretty new to OOP I would need help with this one.
Thanks,
Ile
Create view model:
public class DinnerViewModel
{
public List<Dinner> Dinners { get; set; }
public int NumberOfAllDinners { get; set; }
}
public ActionResult Index()
{
var dinners = dinnerRepository.FindUpComingDinners().ToList();
var numberOfAllDinners = dinnerRepository.FindAllDinners().Count();
return View(new DinnerViewModel { Dinners = dinners, NumberOfAllDinners = numberOfAllDinners } );
}
You need to create a "wrapper" object that contains the objects you wish to pass as public properties of it. For instance, create an object called DinnerViewModel and give it two properties and set these with two properties, one a List called Dinners and one an int called DinnerCount. Then pass the DinnerViewModel to the view and you can then access Model.Dinners and Model.DinnerCount
In your case I would prefer the solution mentioned by LukLed.
In general you could of course also transfer multiple values from your controller to your view using ViewData:
ViewData["dinners"] = dinners;
ViewData["numberOfAllDinners"] = 150;
...
For more information also take a look at this link.
Just simply use dinners.Count property instead.
Remember, you start off using the ViewData inherts in you .aspx filesand returning the same in you return statements. Because of that, I figure that it was an issue with the Inherits attribute on the top of the ASP.NET files. But, if you are getting the error when trying to create or edit a new Dinner when you are on the 'Upcoming Dinners' page (generated from the Details.aspx and the LINQ file that gets all Dinners that are after todays date), go into your 'Controllers' directory, specifically the DinnerController.cs. Then look at the Edit and or Create methods. the answer lies right here. If you put breakpoints on these methods, you should be able to figure it out. If not, continue reading:
Look where it fails, the 'return...' line. Maybe I am the only person who forgot to change this, but my error is the same as people are getting in this page and this os how I fixed it.....the 'return(dinner)' line, in Create and Edit (and any others that you are having issues with), they are using the NerDinner.Model.Dinner / ViewData method. However, if you change it to the ViewModel return method instead, it should fix it, For example: 'return(new DinnerFormViewModel(dinner));', it should work for you. I hope this helps, as it was what my issue was. Just a simple overlook.

Resources