I have been trying to create a simple portal to track logs from a mobile application. As such, I have used entity framework and MVC3 to help me with this. However recently I have been stuck when trying to retrieve the entity from the database.
Here is the Run class:
namespace LifestyleGuide.Models
{
[DataContract(IsReference = true)]
[KnownType(typeof(User))]
public partial class Run
{
[DataMember]
public string User_ID { get; set; }
[DataMember]
public System.DateTime Date { get; set; }
[DataMember]
public Nullable<int> Distance { get; set; }
[DataMember]
public Nullable<int> Duration { get; set; }
[DataMember]
public Nullable<int> Calories { get; set; }
[DataMember]
public virtual User User { get; set; }
}
}
User_ID and date are form a composite key where User_ID is a foreign key from the User table.
And the following is the "details" method from the controller:
public ActionResult Details(String id, DateTime date)
{
using (var db = new inspireEntities())
{
Run run = db.Runs.Find(id, date);
return View(run);
}
}
However, when i try to run it, the run object always appears as a null.
Any suggestions are greatly appreciated!
EDIT:
Here are is the view for the homepage.
#model IEnumerable<LifestyleGuide.Models.Run>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
<center>User ID</center>
</th>
<th>
<center>Date</center>
</th>
<th>
<center>Distance</center>
</th>
<th>
<center>Duration</center>
</th>
<th>
<center>Calories</center>
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.User_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Distance)
</td>
<td>
#Html.DisplayFor(modelItem => item.Duration)
</td>
<td>
#Html.DisplayFor(modelItem => item.Calories)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.User_ID, date = item.Date }) |
#Html.ActionLink("Details", "Details", new { id = item.User_ID, date = item.Date }) |
#Html.ActionLink("Delete", "Delete", new { id = item.User_ID, date = item.Date })
</td>
</tr>
}
</table>
The fields in the table are populated from the database directly and therefore should already exist.
Note: I have no problems with creating and accessing the run objects by using the view. The null run object only occurs when I directly do an insert statement into the database and when i try to retrieve it afterwards using the .find method as shown above.
Find() function returns first occurrence of matching item from the Collection which will be a single item that matched the condition. Since your view is strongly typed to IEnumerable<LifestyleGuide.Models.Run>, it's expecting a collection of Run objects not a single object.
You should modify your controller so that a collection (list) of Run objects are passed to the view. You could use WHERE clause like this :
public ActionResult Details(String id, DateTime date)
{
using (var db = new inspireEntities())
{
List<Run> run = db.Runs.Where(r=>r.Id==id && r=>r.Date==date);
return View(run);
}
}
Good luck :).
I realized the problem! Each entry to the database has a DateTime object with milliseconds while the query doesn't. I did a work-around to remove the milliseconds from all entries and it works!
Related
I have the following code in the View.
<span>#Html.DisplayFor(modelItem => item.comments.comments_id)</span>
<span>#item.comments.comments_id</span>
The code below works if comments_id is not 0 or empty.
<span>#((item.comments.comments_id == 0) ? 0 : #item.comments.comments_id)</span>
If its 0 or empty I get
System.NullReferenceException: Object reference not set to an instance of an object.
The class contains this
public Nullable<int> comments_id { get; set; }
How can overcome this issue? thanks in advance.
---- EDit more code ---
public ActionResult Show()
{
var showItems = db.Projects.Include(p => p.Comments).ToList(); // INCLUDES ITEMS FROM BOTH TABLES
return View(showItems);
}
View
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments.comments_id) // NOTICE this coming from a different table(Comments tbl).
</td>
<td>
<span>#((item.Comments.comments_id == 0) ? 0 : #item.Comments.comments_id) // HERE when item.Comments.comments_id has no contents it throws an error.
Create
</td>
</tr>
}
Someone posted something similar but I don't understand the answer.
http://forums.asp.net/t/1732717.aspx?How+to+check+if+model+property+is+empty+in+View+page
You need to use HasValue to check if a nullable variable has a value or not.
<span>#((item.comments.comments_id.HasValue) ? #item.comments.comments_id : 0)</span>
EDIT: Added Example
Your view code looks like it should work. Below is code I wrote to test your view. The lambda expression in your controller action won't be executed until it's used. So it's possible it's not executed until the view is rendered. This could cause a problem because the database connection may be closed by then. However, the call to ToList() should execute the lambda expression. So the problem is probably that item.Comments is null. You should test to see if it is as I did in my example.
Controller
public class HomeController : Controller
{
public class Project
{
public string ProjectName { get; set; }
public ProjectComments Comments { get; set; }
}
public class ProjectComments
{
public string Comments { get; set; }
public Nullable<int> comments_id { get; set; }
}
public ActionResult Index()
{
var showItems = new List<Project>();
showItems.Add(new Project()
{
ProjectName = "Project 1",
Comments = new ProjectComments() { Comments = "some comments", comments_id = 1 }
});
showItems.Add(new Project()
{
ProjectName = "Project 2",
Comments = new ProjectComments() { Comments = "more comments", comments_id = null }
});
return View(showItems);
}
}
View
#model IList<MvcApplication2.Controllers.HomeController.Project>
<table border="1">
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments.comments_id)
</td>
<td>
<span>
#((item.Comments != null && item.Comments.comments_id.HasValue) ? #item.Comments.comments_id : 0)
Create
</span>
</td>
</tr>
}
</table>
this is my controller code:
var myquery = mycontext.Websites.Select(x => new {x.pagetype,x.website1,x.creationdate,x.expirationdate,x.domainregistrar,x.area,x.pin
,x.city, age = DateTime.Now.Subtract(x.expirationdate ?? DateTime.Today)
});
return View(myquery);
and this is my view code:
#foreach (var item in Model)
{
<tr>
<td>
<span>#item.pagetype </span>
</td>
</tr>
}
how ever its giving me error: object does not contain definition of pagetype while traversing through foreach loop?
i wonder why?
EDIT:
I tried changing the code as below:
Controller:
CRMDataContext mycontext = new CRMDataContext();
var myquery = mycontext.Websites.Select(x => new WebsiteViewModel
{
pagetype = x.pagetype,
site = x.site,
creationdate = x.creationdate ?? DateTime.Today,
expirationdate = x.expirationdate ?? DateTime.Today,
domain_registrar = x.domainregistrar,
Area = x.area,
pin = x.pin,
City = x.city,
difference = DateTime.Now.Subtract(x.expirationdate ?? DateTime.Today).ToString()
}).ToList();
return View(myquery);
but i'm getting exception:
Operation could destablize operation at runtime. Make sure your application is not loading two conflicting version of class library
all i can think..is linq generated class for Website table and my Websiteview model is conflicting . but i can not understand why?
To elaborate on the comment by MarcinJuraszek above, you need to create a view model class to hold these properties.
ViewModel class
public class MyViewModel{
public string Pagetype {get;set;}
public string Website1 {get;set;}
public DateTime Creationdate {get;set;}
public DateTime Expirationdate {get;set;}
public string Domainregistrar {get;set;}
public string Area {get;set;}
public string Pin {get;set;}
public string City {get;set;}
public int Age {get;set;}
}
Now, in your query, select into the ViewModel class
var model = mycontext.Websites.Select(x => new MyViewModel{
PageType = x.pagetype
WebSite1 = x.website1
CreationDate = x.creationdate
ExpirationDate = x.expirationdate
DomainRegistrar = x.domainregistrar
Area = x.area
Pin = x.pin
City = x.city,
Age =DateTime.Now.Subtract(x.expirationdate ?? DateTime.Today)
}).ToList();
return View(model);
And now, you need to strongly type your view and you will be good to go!
#model IEnumerable<MyViewModel>
#foreach (var item in Model)
{
<tr>
<td>
<span>#item.Pagetype </span>
</td>
</tr>
}
After 1 whole day i could solve it out like below:
public WebSiteViewModel
{
string PageType { get; set;}
string WebSite { get; set;}
DateTime CreationDate { get; set;}
DateTime ExpirationDate { get; set;}
string DomainRegistrar { get; set;}
string Area { get; set;}
string Pin { get; set;}
string City { get; set;}
DateTime Age {get; set;}
//Constructor
public WebSiteViewModel(YourWebSiteEntity w)
{
PageType = w.pagetype;
WebSite = w.website1;
CreationDate = w.creationdate;
ExpirationDate = x.expirationdate;
DomainRegistrar = x.domainregistrar;
Area = x.area;
Pin = x.pin;
City = x.city;
Age = DateTime.Now.Subtract(x.expirationdate ?? DateTime.Today);
}
}
controller:
public ActionResult Index()
{
CRMDataContext mycontext = new CRMDataContext();
var myquery = mycontext.Websites.Select(x => new WebsiteViewModel(x.pagetype,
x.site, x.creationdate ?? DateTime.Today, x.expirationdate ?? DateTime.Today, x.domainregistrar, x.pin, x.area, x.city, "Abc")).ToList();
return View(myquery);
}
View:
#model IEnumerable<ImportFromExcel.Model.WebsiteViewModel>
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<table>
<tr>
<th>
Page type
</th>
<th>
Website
</th>
<th>
Creation date
</th>
<th>
Expiration Date
</th>
<th>
difference
</th>
<th>
Domain Registrar
</th>
<th>
Pin
</th>
<th>
Area
</th>
<th>
City
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
<span>#item.pagetype </span>
</td>
<td>
<span>#item.site </span>
</td>
..so on
</tr>
}
</table>
Hope some body else could find it useful as well. Problem was i was not using WebsiteViewModel Constructor to initiliaze model object . this solved my problem atlast. :)
I'm having a hard time getting the values from a small multiple choice questionnaire posted to the Controller in my MVC4 app:
The model looks like this:
public class Evaluation
{
public int Id { get; set; }
public IEnumerable<MultipleChoiceQuestion> Question { get; set; }
public Remark Rem { get; set; }
}
public class MultipleChoiceQuestion
{
public int Id { get; set; }
public string Question { get; set; }
public MultipleChoiceAnswer Answer { get; set; }
}
public enum MultipleChoiceAnswer
{
DISAGREE,
NEUTRAL,
AGREE,
NA,
}
This is the View (leaving out some markup):
#model Models.Evaluation
#using (Html.BeginForm("EvaluationB", "Evaluation", FormMethod.Post))
{
#foreach (var item in Model.Question)
{
#Html.DisplayFor(model => item.Question)
#Html.EditorFor(model => item.Question, "Enum_RadioButtonList", new { Id = item.Id })
}
#Html.Label("Remark")
#Html.TextAreaFor(model => model.Rem)
<input type="submit" value="Next" />
}
The "Enum_RadioButtonList" is a View a grabbed from here: https://gist.github.com/973482. It seems like the best way to show enum values in a radiobuttonlist (tho their should be an easier way in MVC 4)
The Controller looks like this:
public ActionResult EvaluationA()
{
Models.Evaluation evm = new Models.Evaluation();
evm.Question = db.MultipleChoiceQuestions.ToList(); //feeding the View some predefined questions
return View(evm);
}
public ActionResult EvaluationB(Models.Evaluation ev)
{
if (ModelState.IsValid)
{
// TODO: save model
return View("EvaluationB", evm);
}
return View("EvaluationA", ev);
}
The questions are loaded fine in the View, but for some reason, the model posted to the Controller remains empty after an HttpPost, and i don't understand why.
I did not see the form have mapping for the Id like below:
#Html.HiddenFor(model => model.Id)
Each of the inner collection of question should also have Id so that it is posted along with the form. So inside the foreach loop in your form for each question you can have:
#Html.HiddenFor(model => item.Question.Id)
Also the model has a collection of type MultipleChoiceQuestion. For model binding to the collection the name of the collection elements should have name attribute with ordered numbers as explained in this post http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Ive done some more research stumbled upon this post:
http://dotnetslackers.com/articles/aspnet/Understanding-ASP-NET-MVC-Model-Binding.aspx
The problem was in the naming of the html fields. Ive added my View like this and now i can read out the values in the Controller correctly:
#for (int i = 0; i < 6; i++)
{
<tr>
<td>
#Html.DisplayFor(m => m.Question[i].Question)
</td>
<td class="mult_question">
#Html.EditorFor(m => m.Question[i].Answer, "Enum_RadioButtonList" )
</td>
</tr>
}
<tr>
<td>
#Html.Label("Remark")
#Html.TextAreaFor(m => m.Remark)
i'm new at this tecnology and i'm having some trouble passing a list of an excel that i imported to my application, here's the code:
The problems is that the model in the Create Controller comes out null so i cant save into the database.
I can't save it before, in the uploadcomplete action because i intend to edit the values before save into the data base.
[HttpPost]
public ActionResult Index(HttpPostedFileBase excelFile)
{
if (excelFile != null)
{
//Save the uploaded file to the disc.
string savedFileName = Server.MapPath("~/UploadedExcelDocuments/" + excelFile.FileName);
excelFileHandler.ImportExcel(savedFileName, excelFile);
return RedirecToAction("UploadComplete",excelFileHandler.DataToEdit);
}
else { return RedirectToAction("Error", "Upload"); }
}
public ActionResult UploadComplete(List<Persona> DataToEdit) // This comes out null so i cant render the view now
{
return View();
}
[HttpPost]
public ActionResult UploadComplete(IEnumerable<ExcelImport.Persona> model)
{
return View();
}
public ActionResult Create(IEnumerable<ExcelImport.Models.Person> model)
{
using (ExcelimportDBTestEntities context = new ExcelimportDBTestEntities())
{
foreach (ExcelImport.Models.Person person in model)
{
Persona newPerson = new Person();
newPersona.Id = person.Id;
newPersona.Birthday= persona.Birthday;
newPersona.LastName= persona.LastName;
newPersona.Name = persona.Name;
context.Persons.AddObject(newPersona);
context.SaveChanges();
}
return View();
}
}
This is my View, there must be something wrong here
#model IEnumerable<ExcelImport.Models.Person>
#{
ViewBag.Title = "UploadComplete";
}
<h2>UploadComplete</h2>
#Html.BeginForm(){
<table>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Last Name
</th>
<th>
Birthday
</th>
<th>
Options
</th>
</tr>
#foreach (var item in Model) {
#Html.HiddenFor(model => item)
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Birthday)
</td>
<td>
</td>
</tr>
}
</table>
<input type="submit" value="Upload!"/>
}
EDIT: i was tired yesterday so i put some... lets go whit "test" that i was doing by error, now this is what i really want to do. I got an Index View that upload the file and send to the post Index Controller, from there i want to send the list to my UploadComplete Controller, so i can render the UploadComplete View (the list comes out null), and in the post of that Action i want to send the model that i render in the UploadComplete View, to my create controller, so i can storage my data into the database. And as i said before i cant save it into the datebase in the index action becouse i intend to edit this data in the uploadcomplete view.
Thanks in advance, Regards.
As I can see in your code:
There is no [HttpPost] attribute
Form action is GET
Incorrect page rendering (hidden elemens)
Look at this example. It shows how lists could be binded on POST.
I have a view model that looks like this
public class ViewModelRound2
{
public Bid Bid { get; set; }
public bool SelectedForRound2 { get; set; }
}
I have a get action method that looks like this
public ActionResult Round2Manager(long id)
{
...
return View(round1Ring3Bids);
}
And a post method that looks like this (not implemented it yet)
[HttpPost]
public ActionResult Round2Manager(IEnumerable<ViewModelRound2> viewModelRound2)
{
return View(viewModelRound2);
}
My view looks like this
#for (var x = 0; x < Model.Count(); x++)
{
ViewModelRound2 viewModelRound2 = Model.ElementAt(x);
Bid bid = viewModelRound2.Bid;
string userName = #bid.User.Invitation.Where(i => i.AuctionId == bid.Lot.Lot_Auction_ID).First().User.User_Username;
<tr>
<td>
#userName
</td>
<td>
#bid.Bid_Value
</td>
<td>
#Html.EditorFor(c => c.ElementAt(x).SelectedForRound2)
</td>
</tr>
}
</table>
<div class="buttonwrapper2">
#Ajax.ActionLink("Select", "Round2Manager", new { viewModelRound2 = Model }, new AjaxOptions() { HttpMethod = "POST"} )
</div>
The page this renders, contains checkboxes per row in the rendered table and I want to be able to pass checked/unchecked values to the post method so that it can process them. The problem is that the viewModelRound2 parameter of the post method is always null. What is going on? How can I write this so that it does what I intend?
You should put all that HTML inside a <form>.