Hello I have something like this:
public ActionResult Edit(int id)
{
var movie = (from m in _db.Movies where m.Id == id select m).First();
return View(movie);
}
[HttpPost]
public ActionResult Edit(Movie movie)
{
try
{
var originalMovie = (from m in _db.Movies where m.Id == movie.Id select m).First();
_db.Movies.ApplyCurrentValues(movie);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
This example was taken from Proper way to Edit an entity in MVC 3 with the Entity Framework using Data Model First approach?
I want to pass to the DB SQL-query (UPDATE Movie ....) only modified columns because I'm doing a column audit.
The code works ok, but the problem is that in my "Movie" Entity I have a "FlagOldMovie" property and others 10 properties witch I'm not using its in this view because they will stay the same, but the entityframework put to that properties defaults values so the "ApplyCurrentValues" find changes and that properties are updated too.
A workaround is to pass my not changed properties to html hidden inputs, but its privated data.
Any idea?
[HttpPost]
public ActionResult Edit([Bind(Exclude ="column_name")] Movie movie)
{
//code here
}
This would ignore the column you specify, I usually do that to exclude fields like Id.
But if you are ignoring to many columns then you should consider ViewModel concept where you just have only properties you need for a view.
EDIT: Still some issues?
Here is how you add multiple ones
[HttpPost]
public ActionResult Edit([Bind(Exclude ="c_name, c_name2, c_name3")] Movie movie)
{
//code here
}
You can tell EF which fields you want to update. Try something like this:
_db.Movies.Attach(movie);
ObjectStateEntry entryToUpdate = db.ObjectStateManager.GetObjectStateEntry(movie);
entryToUpdate.SetModifiedProperty("field1"); // Replace "field1" with the name of the 1st field to update
entryToUpdate.SetModifiedProperty("field2"); // Replace "field2" with the name of the 2nd field to update
entryToUpdate.SetModifiedProperty("field3"); // Replace "field3" with the name of the 3rd field to update
_db.SaveChanges();
Best practice is to use a ViewModel and not a domain/data model to pass to/from your views. :)
This scenario illustrates one of the dangers of not doing so.
I finally got it, first at all, the solution only works on .NET 4.5+
[HttpPost]
public ActionResult Edit(Movie movie)
{
try
{
//Get DB version
var originalMovie = (from m in _db.Movies where m.Id == movie.Id select m).First();
//Mark changes with data received
_db.Movies.ApplyCurrentValues(movie);
//CODE ADDED - Ignoring field/properties you dont want to update to DB
ObjectStateEntry entryToUpdate = db.ObjectStateManager.GetObjectStateEntry(originalMovil);
entryToUpdate.RejectPropertyChanges("field1");
entryToUpdate.RejectPropertyChanges("field2");
entryToUpdate.RejectPropertyChanges("field3");
//-----------------
_db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
With this code, the only data modified is witch you want, next what I did is to audit columns changed extending _db.SaveChanges() to _db.SaveChangesAudito(id);
try like that
var originalMovie = (from m in _db.Movies where m.Id == movie.Id select m).First();
originalMovie.updateme = updating;
_db.SaveChanges();
Related
I am having some trouble and cannot figure out why my sql database is returning the first data entry as all the other entries.This is my method to get all the database table entries from the table called HealthDataFuture
[HttpPost]
public IActionResult AjaxMethod(string id)
{
List<object> chartData = new List<object>();
chartData.Add(new object[]
{
"Months", "SOFAS"
});
//FOR SOME REASON IT KEEPS READING THE FIRST DATABASE ENTRY ONLY SO THERE ALL THE ENTRIES ARE THE SAME VALUE
foreach (HealthDataFuture data in _db.HealthDataFuture)
{
if (data.id == id)
{
chartData.Add(new object[]
{
data.Month, data.Sofas
});
}
}
return Json(chartData);
}
This is my database table entries, it's returning the first entry as all the other ones when I query all of it, they have the same id because i want to return all of them and then graph
This is the results i keep getting back
i have also tried this way of getting data however it is the same problem
-------EDIT ----- PROBLEM RESOLVED
It turns out my MYSQL table model was not created properly as there was no primary key nor foreign key
It's better not to share image, but code using correct tag. To use code helps other users and all the cummunity, for example it makes your question searchable.
Anyway you can try to do in this way:
if (!string.IsNullOrEmpty(id)){
List<HealthDataFuture> DataList = _db.HealthDataFuture.Where(x => h.Id == id).ToList();
return View(id);
}
return RedirectToAction("Index");
I've also some question about your code:
What should it do?
DataList is like a select query from db, but nobody is using DataList. Why?
The more details you provide, the more information we have to help you.
Editing after comments:
If you want to remove data from db you should use saveChanges. For example, if you want to remove all lines with id other than "1", you can try:
if (!string.IsNullOrEmpty(id)){
_db.HealthDataFuture.RemoveRange(_db.HealthDataFuture.Where(x => h.Id != id));
_db.SaveChanges();
return View(id);
}
return RedirectToAction("Index");
You can also read something about access to DB in async way, it's recommended and it perfoms better: https://learn.microsoft.com/it-it/ef/core/miscellaneous/async
We have a design paradigm we are considering standardizing to but it has some problems and none of us have a good solution for it.
1) We create a core model that contains all the general fields and index values of any foreign keys. This is tied to a table and in our design will be edited in a popup from our grids.
2) a second class inherits the first one and has all foreign key references. This class would populate grids. This would allow us to show specific info from foreign tables.
Now for the Problem: The popup model must match the model for the grid (we are using telerik grids) and when we save, EF tries to validate anything even remotely connected to the table through the foreign keys and anything they reference through foreign keys etc. We once had a record throw an error because we tried to edit an order and the truck assigned to the order's driver was missing mileage info.
I tried (successfully) to replace foreign key references with notmapped fields and load them in the index file but it was slow compared to EF. I looped through each record in the grid (for each) and looked up each matching model and added it.
Another programmer got around the problem by creating two completely different models and having the 2nd model with the foreign keys point to an alias of the table. Personally this feels illegal to me.
Our third developer did something similar but pulled data from a view. He actually had a good reason though as the view had a calculated "locked" column based on financial settlement.
So there you have it. Three different methods to solve the same issue. I've also tried "exclude" from the post but i was evidently doing it wrong.
We considered shutting off the validation in EF but nobody is familiar enough with it to know if it kills the validation on that page as well. MVC is a recent step for us. Our site was originally in asp. The driving force in fact was our orders grid which could take a minute to load.
**So after i gave you all that info, here's the question: ** What is the best way to set our models up? I am the junior programmer and feel like we are doing it wrong in all three scenarios. More importantly i feel like it's completely unnecessary. I would like to bind a model to a grid with full data that inherits a core model but that's all we validate. How is that done?
Example controller:
namespace DispatchCrude.Controllers
{
[Authorize(Roles = "viewShipperTimeCardWorkTypeRates")]
public class ShipperTimeCardWorkTypeRatesController : _DBController
{
[HttpGet]
public ActionResult Index(int? orderid, int? typeid)
{
// Send through any filters
if (orderid != null)
ViewBag.OrderID = orderid;
if (typeid != null)
ViewBag.TypeID = typeid;
return View();
}
// Read
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
virtual public ContentResult Read([DataSourceRequest] DataSourceRequest request = null, int id = 0, int? orderid = null)
{
return Read(request, null, id, orderid);
}
protected ContentResult Read([DataSourceRequest] DataSourceRequest request, ModelStateDictionary modelState, int id = 0, int? orderid = null)
{
var data = db.ShipperTimeCardWorkTypeRates
.Where(m => m.ID == id || id == 0).ToList();
if (orderid != null)
{
var validRates = db.Database.SqlQuery<int>(#"SELECT R.ID
FROM dbo.viewOrder O
CROSS APPLY dbo.fnShipperTimeCardRates(isnull(O.OrderDate, O.DueDate), null, null,
O.TicketTypeID, O.DestTicketTypeID, O.CustomerID, CarrierTypeID, O.CarrierID, DriverGroupID, O.DriverID, O.TruckTypeID, O.ProductGroupID,
O.DestinationID, O.OriginID, O.DestStateID, O.OriginStateID, O.DestRegionID, O.OriginRegionID, O.ProducerID, 0) R
WHERE O.ID = " + orderid);
data = data.Where(m => validRates.Contains(m.ID)).ToList();
}
return ToJsonResult(data, request, modelState);
}
// Create
[HttpPost]
[Authorize(Roles = "createShipperTimeCardWorkTypeRates")]
public ActionResult Create([DataSourceRequest] DataSourceRequest request, ShipperTimeCardWorkTypeRateBase timeCardWorkTypeRates)
{
// Create functionality is now taken care of in the update function as of Kevin's 2017 update to how MVC controllers are written
return Update(request, timeCardWorkTypeRates);
}
// Update
[HttpPost]
[Authorize(Roles = "editShipperTimeCardWorkTypeRates")]
public ActionResult Update([DataSourceRequest] DataSourceRequest request, ShipperTimeCardWorkTypeRateBase timeCardWorkTypeRates)
{
try
{
DateTime checkDate1;
DateTime checkDate2;
bool success1 = DateTime.TryParse(timeCardWorkTypeRates.EffectiveDate.ToString(), out checkDate1);
bool success2 = DateTime.TryParse(timeCardWorkTypeRates.EndDate.ToString(), out checkDate2);
if (success1 && success2 && checkDate2.Subtract(checkDate1).TotalHours < 0)
{
ModelState.AddModelError("Update", "End Date must be equal to or later than Start Date.");
}
if (ModelState.IsValid)
{
// Create new record or update existing record
db.AddOrUpdateSave(User.Identity.Name, timeCardWorkTypeRates);
}
}
catch (Exception ex)
{
ModelState.AddModelError("Update", ex.Message); // TODO: use a common routine to "cleanup" db generated errors
return App_Code.JsonStringResult.Create(new[] { timeCardWorkTypeRates }.ToDataSourceResult(request, ModelState));
}
return Read(request, ModelState, timeCardWorkTypeRates.ID);
}
// Delete (Deactivate)
[HttpPost]
[Authorize(Roles = "deleteShipperTimeCardWorkTypeRates")]
public ActionResult Delete([DataSourceRequest] DataSourceRequest request, ShipperTimeCardWorkTypeRateBase shipperTimeCardWorkTypeRate)
{
// Delete the record
db.ShipperTimeCardWorkTypeBases.Attach(shipperTimeCardWorkTypeRate);
db.ShipperTimeCardWorkTypeBases.Remove(shipperTimeCardWorkTypeRate);
db.SaveChanges(User.Identity.Name);
return null;
}
public ContentResult getBestMatch(int orderid, int? typeid = null)
{
string sql = "SELECT DISTINCT ID FROM fnOrderShipperTimeCardRates(" + orderid + ")";
if (typeid != null)
sql += " WHERE WorkTypeID = " + typeid;
var bestmatchids = db.Database.SqlQuery<int>(sql);
return ToJsonResult(bestmatchids.ToList());
}
}
}
`
the popup editor uses #model DispatchCrude.Models.ShipperTimeCardWorkTypeRate
the grid uses the same. This split works but EF won't allow us to set two models to the same table, and the inheriting didn't work either.
What do we do?
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);
}
I encountered a very strange (and annoying) issue:
in MVC 4 web application while loading data from the database and using a foreach on the Model within the view:
#foreach (var meeting in Model)
i have a breakpoint in the method's beginning and examining the object meeting i see that it misses some data (reference to other tables). if I open (+) other object within meeting the missing data appears.
Why?
Thanks!
here is my controller method:
public ActionResult GetMeetingMR(int id = 0)
{
var meetingPurpose = db.MeetingPurposes.ToList();
ViewBag.MeetingPurpose = new SelectList(meetingPurpose, "MeetingPurposeID", "MeetingPurposeName");
ViewBag.MRID = id;
List<Meeting> meetings = (db.MortgageRequests.Find(id)).Meetings.ToList();
return View(meetings);
}
Including your title in your question, my guess is you do not experience the problem (yet) without the debugger attached.
As others have commented it is due to LazyLoading.
The problem may occur sometimes because while rendering the View the entities container is being disposed, most probably because it is collected by the GarbageCollector which calls the destructor of the container.
If you wish to access the entities on your View you can use Include on the ObjectSet.
Let's say MeetingPurposes has an associated EntitySet of Dates:
If you wish to include them in the loadoperation you can do the following:
db.MeetingPurposes.Include("Dates").ToList();
public ActionResult GetMeetingMR(int id = 0)
{
//Load the MeetingPurposes including their dates
var meetingPurpose = db.MeetingPurposes.Include("Dates").ToList();
ViewBag.MeetingPurpose = new SelectList(meetingPurpose,
"MeetingPurposeID",
"MeetingPurposeName");
ViewBag.MRID = id;
List<Meeting> meetings = (db.MortgageRequests.Find(id)).Meetings.ToList();
return View(meetings);
}
If you wish to do this for Meetings and Meetings has an EntitySet of Dates you could do:
public ActionResult GetMeetingMR(int id = 0)
{
var meetingPurpose = db.MeetingPurposes.ToList();
ViewBag.MeetingPurpose = new SelectList(meetingPurpose,
"MeetingPurposeID",
"MeetingPurposeName");
ViewBag.MRID = id;
var meetings = (from mee in db.Meetings.Include("Dates")
join mga in dbo.MortgageRequests.Where(m => m.Id == id)
on mee.MortgageRequestID equals mga.ID
select mee).ToList();
return View(meetings);
}
Not really sure what your Find extension method is so I used a Where on MortgageRequests.
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.