I have a simple row that has 4 columns:
{ [Primary Key Int]RowID, [text]Title, [text]Text, [datetime]Date }
I would like to allow the user to edit this row on a simple page that has a form with the fields "Title" and "Text".
There is a hidden field to store the RowID.
When the user posts this form to my controller action, I want it to update the row's Title and Text, and keep the Date the same. I don't want to have to explicitly include a hidden field for the Date in the form page.
Here is my action:
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow(Row myRow)
{
RowRepository.SaveRow(myRow)
return View("Success");
}
RowRepository:
public void SaveRow(Row myRow)
{
db.MyRows.Attach(myRow);
db.Refresh(RefreshMode.KeepCurrentValues, myRow);
db.SubmitChanges();
}
This dosen't keep the "Date" value already in the row and tries to insert a value that throws an timespan exception.
How can I just tell it to keep the old values?
I tried doing RefreshMode.KeepChanges and nothing.
I'm not in a position to test this at the moment but try making the datetime column nullable and then ensure that the datetime passed into SaveRow has a null value.
Try
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow([Bind(Exclude="Date")] Row myRow) {
RowRepository.SaveRow(myRow)
return View("Success");
}
Update
Try this approach, where there is no 'Date' field on your page
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow(int RowID) {
Row myRow = RowRepository.GetRow(RowID);
UpdateModel(myRow);
RowRepository.Save();
return View("Success");
}
In your repository
public void Save() {
db.SubmitChanges();
}
This will only save the changes made to 'myRow'
You will have add a method in the partial class / override the code it build.
The class Table does implement "INotifyPropertyChanging|ed" which is used to track which column has been changed.
You can hack it and reset the value "this.PropertyChanged".
But what I do at work is a stupid READ-APPLY-WRITE approach (and I am using WebForm).
public void SaveRow(Row myRow)
{
var obj=db.MyRows.Where(c=>c.id==myRow.id).First();
obj.a=myRow.a;
obj.b=myRow.b;
db.SubmitChanges();
}
You can do a bit simpler.
public void SaveRow(Row myRow)
{
db.MyRows.Attach(new Row(){
Id=myRow.Id,
Title=myRow.Title,
Text=myRow.Text,
});
db.SubmitChanges();
}
PS. I am new to LINQ to SQL. Please let me know if there is a smarter way to do it.
Ok, I set it to nullable and it keeps overwriting the database as a null value. I guess its impossible to do this since technically null is a valid value for the column and if I pass an object to the function, the empty values must contain something or be null.
So I would have to explicitly state to take the database value for that column
Thanks
Related
I am using Entity Framework 4.0, and making use of POCO objects. When I populate POCO objects from the DB, I translate property values to my own Domain objects, which we can call my Model.
Necessarily, whether or not the fields of my Model are Nullable depends on whether the value it maps to in the database comes from a NULL or NOT NULL column. I won't go into detail, but the values must be nullable in the DB, because a user can partially save a draft of the object before publishing it to the public. That being the case, I have several fields that are nullable. So let's say my model looks like:
public class MyModel
{
public int? Field1 {get; set; }
public DateTime? Field2 {get; set; }
public int Field3 {get; set; }
}
If I use this Model in my View, complete with nullable fields, I begin receiving errors that tell me I cannot use nullable properties as values in various places, like HTML helpers, etc. I could say something like if (Model.MyBoolField.HasValue && Model.MyBoolField.Value) { // etc }, but that feels bulky for a view.
I considered creating a ViewModel object that inherits from my original domain object and has new, non-nullable versions of my nullable fields that return an appropriate value if the base version is null. So something like:
public class MyViewModel : MyModel
{
public new int Field1
{
get { return base.Field1 ?? 7; }
}
public new DateTime Field2
{
get { return base.Field2 ?? DateTime.Now; }
}
}
My problem with this is that I don't always know a good "default" value to display. What if I threw an exception in the View Model's getter when the base value is null? Is that poor practice?
I'm basically looking for a best practice on how to handle nullable fields in a model, particularly when displaying in a View.
If you just need to display these fields in a View, you don't need to specify or check whether is has a value or not.
Using Model.Field1 in your View file is enough. It will simple not display anything, and it won't throw an exception. You can always use ?? to set a default when it makes sense.
#(Model.Field1 ?? "There is nothing to see here")
In most of the cases I use the "For" helpers, which seem OK with Nullable values (PublishedCount is a nullable property):
#Html.TextBoxFor(m => m.BillPull.PublishedCount, new { id="txtPublishedCount" })
#Html.ValidationMessageFor(m => m.BillPull.PublishedCount)
When I need to use just TextBox, I use the GetValueOrDefault method, with whatever default value the framework provides:
#Html.TextBox("BillPull.AutoPublishDate", Model.BillPull.AutoPublishDate.GetValueOrDefault().ToString(dateFormat), new { id = "dtpAutoPublishDate" })
#Html.ValidationMessageFor(m => m.BillPull.AutoPublishDate)
There is a field in our database which really ought to be a boolean, but for some reason the original developers made it a CHAR which will either be set to "1" or "0".
[Column("CHARGEABLE")]
[StringLength(1)]
private string Chargeable { get; set; }
I want my model to represent this field as a boolean so I figured I could add a property to my model to wrap it:
[NotMapped]
public bool ChargeableTrue
{
get
{
return Chargeable == "1" ? true : false;
}
set
{
Chargeable = value ? "1" : "0";
}
}
Now on my View I just display the EditorFor ( ChargeableTrue ), but when I click save it doesn't actually update it.
I think what is happening is that when the model is being updated, it's still attempting to get the value of 'Chargeable' from the View, even though I haven't displayed it there. And since there is no input field, it just gets null and ends up saving that to the database.
if (ModelState.IsValid)
{
db.Entry(call).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
What is one expected to do in this situation?
Based on KMan's answer, here's the extended version just in case you're not familiar with creating view models.
The idea is that your domain object is not really what you want to be updating exactly from your views. Instead, you create a go-between that can also include view-specific items (like a list of objects to populate a drop-down).
public class MyViewModel {
public bool Chargeable { get; set; }
}
Now you can do this:
#* In view *#
Html.EditorFor(m => m.Chargeable)
// In controller
public ActionResult Save(MyViewModel model) {
if (ModelState.IsValid) {
var domainObject = new MyObject() {
Chargeable = model.Chargeable ? "1" : "0"
};
// the rest of your code using domainObject
}
}
I'd consider just creating an overload of your domain object's constructor that accepts your view model to keep the mapping in one place. I typically use a tool like AutoMapper to map objects or manual extension methods.
A view model typically contains a sub-set of your domain object's properties, but can contain all of them or more properties like lists, visbility states, etc. They come in incredibly useful and I've never done a MVC project where I haven't used them.
Use a view model and make your mapping on the controller.
Does anyone happen to know if there is a way in the Entity Framework to return me the Guid of a just inserted row, assume the column is an guid which is auto Generated.
I am using MVC with Entity Framework. I am using Repository Method ADD(), the return type of the method is void.
Any one knows?
StewieFG,
On adding the item, and hitting SaveChanges(), your object should now be populated with the value of the autogenrated column. Consider the example below:
[HttpPost]
public ActionResult Create(MyEditViewModel viewModel)
{
if (ModelState.IsValid) {
_myService.Insert(viewModel.Entity);
_myService.SaveChanges();
// we can query the column value for the autogenerated value now
// i.e. viewModel.Entity.GuidIDColumn value etc..
return this.RedirectToAction(x => x.Index());
} else {
PopulateViewModel(viewModel);
return View(viewModel);
}
}
hope this helps
I have a column in the database which is Name its string with null value.
when I dont enter anything in the Name Field its saving to the database as NULL.
but I need to save this value as string.Empty or "".
I did soemthing like this.
h.assignedName= m.Name== null ? string.Empty : m.Name;
ViewModel Property has
Public string Name {get;set;}
my question is any other way we can assign this value has String.Empty without doing any condition like above?
I dont want to use ? operator to check the condition or if condition.
Thanks
You could change the column in the database to not be NULL and set the default value to ''. That way you would not have to use the ? conditional. Not sure if this is best practise, but it would save you having to add additional code to cater for it.
The other way is to create a wrapper class around the data. I see you're using m.Name in your code example. You could have:
public class MyWrapper
{
private string _name;
public string Name
{
get {
if (String.IsNullOrEmpty(_name)){
return String.Empty;
}
return _name;
}
set{
_name = value;
}
}
}
So when you're reading the data from the database, create an instance of your wrapper class to hide the details when getting the Name.
Jason's idea is sound assuming you do not care about making that minor change.
Another way you could do it is to abandon your automatic property and handle the checking in the get
private string name;
public string Name
{
get { return (name == null) ? string.Empty : name; }
}
This obviously has more initial code over head for all properties that you want to utilize this style.
or you could ensure it is never null in your constructors
You might consider changing the layout of your code construction and use a business rule like
"m.Name may never be null." And then you should initialize it as String.Empty, so that it can never be null.
i am kind of stuck with this code:
[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Edit(FormCollection collection, [Bind(Exclude="Id,Latitude,Longitude")]Store bindStore, string Latitude, string Longitude)
{
Store st = storeModel.GetStore(Session["user_id"].ToString());
bool modelUpdate = TryUpdateModel(st, new string[] { "Storename", "Address1", "Address2", "Zipcode", "City", "Phone1", "Phone2", "Store_email", "Store_homepage", "Pm_ec", "Pm_visa", "Pm_master", "Appointment_requirement", "Short_user_store_description" });
if (ModelState.IsValid)
{
storeModel.Save();
return RedirectToAction("ImageUpload");
}
else
return Edit();
}
My problem is, that i don't know whats the right way to do the ModelBinding, when i need these conditions to match:
The "Store" object has several fields ( not only Id ) that should NOT be updated during this update ( had problems that the "TryUpdateModel" NULL-ifies all these fields, so i added the "includeProperties" value with the cleartext of all the params.. a solution i don't like anyway)
Getting the store id from session as i don't want it to be in the HTML
Making InputValidation through the DataAnnotationModel ( see below )
[MetadataType(typeof(StoreMetaData))]
public partial class Store
{
}
public class StoreMetaData
{
[Required]
[StringLength(5)]
public object Storename { get; set; }
}
Question: Is this the right approach or is there a standard/nicer solution for this kind of problem?
You don't need formcollection in parameters for start.
And no, updatemodel will try to update all fields of model if no white or black list defined.
So either that or create your own function to update your model objects.
Maybe somethig generic. that will reflection enumerate properties of supplied update object and apply those that are not null to object being updated.
My guess, from looking at the code you posted, is that you're trying to make it so that the Edit view will only allow certain fields to be edited, but 'pass through' the ones you don't want changed. In that case, you can modify your Edit view to remove those fields from being edited, but still send them over in the form using:
<%= Html.Hidden("field") %>
Let me know if this is what you intended.
Your way is fine IMHO.
There are other options but none of them provide a compelling benefit over your technique.
The only thing I would do differently is to model bind to custom ViewModel with the exact fields you need and then do the rightly-lefty code to assign just those values:
public ActionResult Edit( SlimStoreViewmodel editStoreModel, string Latitude, string Longitude)
{
Store st = storeModel.GetStore(Session["user_id"].ToString());
if (ModelState.IsValid)
{
st.Thing = editStoreModel.Thing;
st.Thing2 = editStoreModel.Thing2;
st.Widget = editStoreMOdel.Widget;
storeModel.Save();
return RedirectToAction("ImageUpload");
}
else
return Edit();
}
This gets rid of long magic string dense things like this:
TryUpdateModel(st, new string[] { "Storename", "Address1", "Address2", "Zipcode", "City", "Phone1", "Phone2", "Store_email", "Store_homepage", "Pm_ec", "Pm_visa", "Pm_master", "Appointment_requirement", "Short_user_store_description" });