I currently have a model that is passing a dogs variable into the view:
public ActionResult Summary()
{
var dogs = repository.GetAllRecords().OrderByDescending(x => x.DateRecieved);
return View("Summary", dogs);
}
This has a field in it called OutcomeID, which references another array by ID:
var categories = new List<Category>();
try
{
this.Connect();
var cmd = new SqlCommand
{
CommandText = "dbo.GetSummaryOutcomes",
CommandType = CommandType.StoredProcedure,
Connection = this.cn
};
var result = cmd.ExecuteReader();
while (result.Read())
{
categories.Add(new Category
{
Name = result["Outcome"].ToString(),
Value = result["id"].ToString(),
InUse = bool.Parse(result["InUse"].ToString())
});
}
}
Is there anyway so that on my view I can combine these, and instead of just having the OutcomeID, I reference the Outcome result from the categories list?
ie I need to get result["Outcome"] based on matching dogs.OutcomeID to result["id"]
Sorry if this sounds like a silly question, in PHP this wouldn't be a problem for me, but I'm very new to ASP.NET MVC and I'm not sure where to begin
Thank you
You can create a View Model which is a common practice in ASP.NET MVC, basically you will have to create a new class with the properties that you need to pass on to your view, then in your controller you will send the instace of the view model to your view and also transform your data into the viewmodel.
Have a look here ASP.NET MVC - How exactly to use View Models. Also you might want to have a look at automapper, which is a mapping library that removes a lot of the boilerplate code involved when working with view models.
Related
I have two database tables that are linked by an attribute in one of the tables. The tables are being separately represented as models in an ASP .NET core MVC app. In a controller action, I have a linq query that performs a join on the two tables and selects a set of columns from the join results. I'm trying to send this result set to a view page so that the data can be displayed in a paginated table, but I'm not sure how exactly this should be done.
In the past, when using ASP .NET MVC (not core), I've been able to execute stored procedures that return result sets in controller actions, iterate through the result sets, build up lists with the data and then store the lists in the viewbag which can be accessed in the view. I've tried to directly store the EntityQueryable object in the viewbag but I got an error and I'm not sure how I would go about iterating through it anyway.
What would be the best way to send the data returned from the linq query to the View page?
Controller Action code:
var resultsObj = (from rd in _db.ResData
join ra in _db.ResAvailability on rd.RecNo equals ra.RecNoDate
where ra.TotalPrice < Int32.Parse(resDeals.priceHighEnd) && ra.TotalPrice > Int32.Parse(resDeals.priceLowEnd)
select new
{
Name = rd.Name,
ImageUrl = rd.ImageUrl,
ResortDetails = rd.ResortDetails,
CheckIn = ra.CheckIn,
Address = rd.Address,
TotalPrice = ra.TotalPrice
}).Take(10);
ViewBag.resultSet = resultsObj;
EDIT:
My query is returning data that from multiple tables (since it is a join) so data from the query results has to
be extracted and separated into the two different viewmodels which correspond to the tables in the join.
The first viewmodel represents each row of the query results. The second viewmodel is just a list to hold all of the rows that are contained in the query results.
I'm trying to understand how to do the data extraction from the query results into the viewmodels as I have explained here.
I would return a ViewModel instead. Generally you may use it to send the data to/from the View and controller.
I am currently working on a big project, and ViewModels work pretty well for me.
Check this short video:
https://www.youtube.com/watch?v=m086xSAs9gA
UPDATE
I am assuming that your query works properly (I did not read it).
To send your data via a ViewModel to the View.
First create the required ViewModel classes:
public class PageNameViewModel
{
public string Name { get; set; }
public IEnumerable<ResortDetailViewModel> ResortDetailViewModels { get; set; }
... rest of properties are not shown for clarity ...
}
public class ResortDetailViewModel
{
public string Detail1 { get; set; }
public int Detail2 { get; set; }
... etc. ...
}
Now use the ViewModels in the controller (or let us say, fill the data in the viewmodel):
var viewModel = (from rd in _db.ResData
join ra in _db.ResAvailability on rd.RecNo equals ra.RecNoDate
where ra.TotalPrice < Int32.Parse(resDeals.priceHighEnd) && ra.TotalPrice > Int32.Parse(resDeals.priceLowEnd)
.Take(10)
select new ClassNameViewModel
{
Name = rd.Name,
ImageUrl = rd.ImageUrl,
ResortDetailViewModels = rd.ResortDetails.Select(o =>
new ResortDetailViewModel
{
Detail1 = o.detail1,
Detail2 = o.detail2,
... etc. ...
},
CheckIn = ra.CheckIn,
Address = rd.Address,
TotalPrice = ra.TotalPrice
});
return View(viewModel);
Now you can use the ViewModel in the View (I assume you know how, as you watched the view I linked).
Notice that ViewModels should ideally hold primitive data in this case (that will make your life easier if you plan later to serialize the ViewModel and send it to another client).
In the above code, I converted any complex types to primitive types, and that should be on each element (notice I did the same on ResortResults, as I converted them to an array of ViewModel, i.e., array of an objects that only holds primitive data, so no deep hierarchy).
I also moved Take(10) to the upper side of the code, so you do not need to create a ViewModel for each element, and then take only 10! that is just wasting of performance for nothing. By moving it to the upper side, we take the 10 elements before creating the ViewModels, i.e., we create the ViewModels for only the required elements.
I hope that helps. If you need any further help, please please tell me.
I am refactoring somebody else's app written badly in ASP.NET MVC 4 (Razor). [.NET is not my specialty - I do primarily C/C++]. He is not doing database access the MVC canonical way. He is using a Repository class for each table to execute all of his SQL commands on SQL Server rather than the let the basic Entity Framework do the heavy lifting. The app has to:
read a list of rows from a table from the controller (he has a Model for the table).
return this list of model objects to a view (ViewBag or ViewData would be easiest).
insert the list members in a table or list in the View.
select a single row (representing a from the list return the selected row to a controller ActionResult- a single table record in the model class
In the repository class (partial code) called by the controller:
public List<Note> GetNotesByWorkGroup(string workGroup)
{
List<Note> notes = new List<Note>;
string sql = "SELECT * FROM tblNotes where WorkGroup = 'Foo';
SqlCommand sqlCmd = new SqlCommand(sql, conn);
SqlDataReader myReader = sqlCmd.ExecuteReader();
if (myReader.HasRows)
{
while (myReader.Read())
{
Note note = new Note();
note.NoteId = myReader.GetInt32(NoteIdOrdinal);
note.DateTime = myReader.GetDateTime(DateTimeOrdinal);
note.WrittenBy = myReader.GetString(WrittenByOrdinal);
notes.Add(note);
}
}
return notes;
}
The controller receives this and must pass it to a view. His way of passing the list is:
List<Note> notes = noteRepository.GetNotesByWorkGroup();
ViewData["myList"] = notes;
In the view, he fouled everything up. Simplest solution would be to either create a table or list with an onclick(note.Id) for each element which must be clickable (a button or href?). Each row will need a clickable element and one other text element from the Note object for a two-parm row display.
For example, it would need to look like this, with Date the selectable field and WrittenBy just text.
Date1 WrittenBy
Date2 WrittenBy
Date3 WrittenBy
Then a javascript function can receive the Id onclick() and submit it to the controller ActionResult().
I just need a sample of View code (MVC 4, C#, Razor) showing how the ViewData["myList"] gets dereferenced from C# to HTML and inserted into the rows in the list or table. Also, how would I write a submit in a javascript function that passes a parm?
Any suggestions and examples for the View?
you can perform this task using ViewModel,ViewBag or ViewData approach.
ViewModel
foreach (var item in Model.myList)
{ }
ViewBag or ViewData
You can create a table and then can loop through all data.
<table>
<tr>
<td>date</td>
<td>writtenby</td>
</tr>
#foreach (var item in ViewData["myList"])
{
<tr>
<td>#item.date</td>
<td>#item.writtenby</td>
</tr>
}
</table>
My first suggestion would be return notes from controller instead of setting the View Data
If not you not you shoudl be able to access ViewData["myList"] like an array. ViewData["myList"][0].properyName.
I hope that helps if I can find some sample code, I will update this post.
#{
List<Note> _list = ViewData["myList"] as List<Note>;
}
#if (_list != null)
{
foreach (var item in _list)
{
#Html.ActionLink(item, "Index");
}
}
Try it Hope it will help.Thanks
I have a two questions.
The first one is about that moment when you go to EDM and update your models from database and it rewrites the old models, losing everything you edited inside them. I read a little about this and it is said that you can create another models and make them also partial and there you may put again the fields so at the next update it won't affect your last changes. How can I do this? I have a separate project for my DAL and the models were generated from database (I have an EDM).
The second question is... But better I give an example. I have a model called Categories and another one CategoriesTranslations, both of them mapped from my database. Let's say you want to have a list of this categories inside a DropDownList() in many views of your website (of your different controllers). The DropDrown will have the value containing the translation which depends on the current language and the keys containing the category ID.
Here is an example of my list:
List<SelectListItem> listItems = new List<SelectListItem>();
var CategoriesTexts = db.Categories.Include(i => i.CategoryTexts).ToList();
foreach (var cat in CategoriesTexts)
{
var texts = cat.CategoryTexts.Where(w=>w.Language.Format == (string)Session["chosen_language"]).FirstOrDefault();
listItems.Add(new SelectListItem
{
Text = texts == null ? cat.Id.ToString() : texts.Name,
Value = cat.Id.ToString(),
});
}
Where should I put this code in my website structure (or how can I structure it) to make use of it in most of my Views?
Thank you!
For your first question
There is no need to make partial classes just to fix the naming when you update EF EDMX file. Actually you shouldn't delete the model class from the Edmx when you make update to your database all you need to do is to update the model and it will save your navigation properties names as you made them already.
For your second Question
Although I don't agree with you about what you're doing to get the categories to the DropDownList, But you could make this as Extension method for the IEnumerable<Category> and put this method in ViewModelExtensions project
e.g.
public static IList<SelectListItem> ToDropDownList(this IEnumerable<Category> query)
{
List<SelectListItem> listItems = new List<SelectListItem>();
foreach (var cat in query)
{
var texts = cat.CategoryTexts.Where(w=>w.Language.Format == (string)Session["chosen_language"]).FirstOrDefault();
listItems.Add(new SelectListItem
{
Text = texts == null ? cat.Id.ToString() : texts.Name,
Value = cat.Id.ToString(),
});
}
}
then just call it in your controllers like this:
var list = db.Categories.Include(i => i.CategoryTexts).ToDropDownList();
I have got two different tables. User and ProjectDetails. There are two different controllers as well to do CRUD operations on these tables. Now, I have a case where, in the User CREATE operation, I have to select the Project from the List of Projects in ProjectDetails. I tried the following:
In the user model, I created this line:
public IEnumerable<ProjectDetail> ProjectDetail { get; set; }
And in the controller, in the create Action, I have added the following code:
public ActionResult Create()
{
var model = new UserDetail
{
ProjectDetail = db1.ProjectDetails
};
return View(model);
}
And in the create view, I am trying to get the list of Project IDs as follows:
#Html.DropDownListFor( x => x.ProjectDetail, new SelectList(Model.ProjectDetail, "Project ID"))
However, wen i run, i get the number of lines (as equal to the number of projects) as
System.Data.Entity.DynamicProxies.ProjectDetails_F########### (Some numbers)..
Please can someone help me?
Regards,
Hari
[EDIT] - I checked in the debug mode and found the following.. Tried attaching the image..
I drilled down that Proxy things and found ProjectID there. How can I get that?
You are using a wrong overload, use this instead:
#Html.DropDownListFor( x => x.ProjectDetail,
new SelectList(Model.ProjectDetail, "ProjectId","ProjectName"))
// where ProjectId is the unique identifier field of `ProjectDetail`
// and `ProjectName` is the text you want to show in the dropdown
In your code you are not telling the html helper what properties to use for the datavalue and the datatext. The overload you use is the one where you tell the htmlhelper which value is selected.
You can do something like
var projection = db1.ProjectDetails.Select(t => new ProjectDetailsViewModel
{
Prop1 = t.Prop1,
Prop2 = t.Prop2
});
Can you try
public ActionResult Create()
{
var model = new UserDetail
{
ProjectDetail = db1.ProjectDetails.ToList()
};
return View(model);
}
forgive me as I am fairly new to using ASP.net MVC 3...
I have two tables - one called Contract, one called Sow. Contract has a foreign key that points to SOW. What I'd like to do is to be able to edit the Contract details and provide a drop down list of different SOW records to choose from. The current code:
In my Contract Controller:
public ActionResult Edit(int id)
{
Contract contract = contractRepository.GetContract(id);
var db = new ManagementDataContext();
IEnumerable<SelectListItem> items = db.Sows
.Select(s => new SelectListItem()
{
Value = s.ID.ToString(),
Text = s.Title
});
ViewData["Sow"] = items;
return View(contract);
}
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
Contract contract = contractRepository.GetContract(id);
try
{
UpdateModel(contract);
contractRepository.Save();
return RedirectToAction("Details", new {id = contract.contractID});
}
catch
{
ModelState.AddRuleViolations(contract.GetRuleViolations());
var db = new ManagementDataContext();
IEnumerable<SelectListItem> items = db.Sows
.Select(s => new SelectListItem()
{
Value = s.ID.ToString(),
Text = s.Title
});
ViewData["Sow"] = items;
return View();
}
}
In my Edit.aspx:
<%: Html.DropDownList("Sow") %>
The list populates with values, but when I change them and update, the foreign key does not change. Any advice or help? Also, if you want to throw in a way I could improve my current code?
Again, I apologize for my lack of ASP.net knowledge, but you gotta get your hands dirty and make mistakes in order to learn.
This is going to generate a select with name="Sow".
What you want is the input to have the same name as the FK property you want to bind it too.
Probably something like <%: Html.DropDownList("SowId") %>
Firstly, I highly recommend you to use ViewModel pattern with AutoMapper.
Whatever, in you scenario, should work if you do something like
public ActionResult Edit(int id)
{
Contract contract = contractRepository.GetContract(id);
var db = new ManagementDataContext();
IEnumerable<SelectListItem> items = db.Sows
.Select(s => new SelectListItem()
{
Value = s.ID.ToString(),
Text = s.Title
});
ViewData["SowItems"] = items;
return View(contract);
}
Your view:
<%: Html.DropDownList("SowId", ViewData["SowItems"]) %>
the possible problem can be with ModelState and I can't right now give to you a clear explanation.
hope it help you
A few approaches for you to try mixed with some code help.
1st: change your [HttpPost] Edit method to accept a Contract parameter instead of FormCollection, its much cleaner
[HttpPost]
public ActionResult Edit(Contract contract)
As long as the fields of Contract are the names of your input fields, then you are set as the MVC toolkit will map them to a Contract object that is then passed to your Action method.
This will also allow you to take advantage of Unobtrusive Validation, meaning MVC framework will validate the data inputs to your model object before it gets to your Action method. You will still have to perform Business Rule validations or Data Model Relational validations, but it helps.
2nd: I prefer to create SelectLists in the View (probably get killed over this), but I think SelectList is definitely a View abstraction of your data which has nothing to do with Control or Model, here's a way to do it, and here's where a ViewModel comes in handy
[Side note here for ViewModel, it helps get away from using Strings to pull things out as Objects from ViewData, which in some cases (like SelectLists) need to then be cast in order to compile]
Controller code
var model = new ContractViewModel()
{
Contract = contractRepository.GetContract(id),
Sows = db.Sows.ToList() // ToList() is important here to ensure the data is pulled into the Model
}
// Do any other initializations here
ViewData.Model = model;
return View();
View code
<%= Html.DropDownListFor(model => model.Contract.Sow, new SelectList(Model.Sows, "ID", "Title")) %>
An alternative, if either this won't work for you or you need different validations is:
Controller code
[HttpPost]
public ActionResult Edit(Contract contract, int sowID)
View code
<%= Html.DropDownList("sowID", new SelectList(Model.Sows, "ID", "Title")) %>
Hope this helps.