Default Values in LINQ Modelling - asp.net-mvc

To put it in basic form, my database table doesn't allow nulls for varchars, it must have blanks. My model doesn't allow nulls so it won't insert a record if I leave form fields empty. If an empty form field appears I want a default value of blank to be used instead. I've tried, for example, the following without any luck:
[Column]
[DisplayName("WMD Company")]
[DefaultValue(" ")]
public string WMDCompany { get; set; }
So instead, in my controller action I have to do a check like the following:
if(myModel.WMDCompany == null) myModel.WMDCompany = " ";
Which is plain nasty to me. Is there any way of getting [DefaultValue(" ")] to work?
Cheers

What about something like this:
private string wmdCompany;
public string WMDCompany
{
get
{
if (this.wmdCompany == null)
{
return string.Empty;
}
return this.wmdCompany;
}
set
{
this.wmdCompany = value;
}
}

The DefaultValue attribute is not used. LINQ to SQL has not support for DB defaults unfortunately. That property is intended for use in API extension if I remember, but I don't know of any that use it.
Two approaches to get around this you could use.
First update your data layer, by appropriately controlling the property, and setting it to null. Use a partial class to extend your data class, and implement the OnCreated() partial method, and in this set the value to String.Empty.
partial void OnCreated()
{
MyProp = String.Empty;
}
Secondly, you could change your DBML representation to allow nulls, but in your database, use a trigger to convert NULLs to empty strings.
I'd go with the first approach myself - assuming you can't just use NULLs as suggested by Adrian

Inserting spaces as a placeholder for NULL seems like a very obscure method to me. Why don't you just change your table design to allow NULL values?

Related

using Variable property Name with Razor MVC

I am trying to have all the models used for specific searches into one Generic search view.
I need to render only some of the fields in the model, either with something similar to this : (Psudo code)
foreach (string textBoxFieldName in TextBoxFieldNames)
{
Html.Toolbox_TextBoxFor(m => m.textBoxFieldName)
}
or having attributes on the model and checking when that attribute applies e.g.
in the model I'll have something like this :
[AppliedCases("Case1","Case4","Case77")]
[ControlToUse("TextBoxFor")]
public string LastName { get; set; }
And some how in the view will be able to go trough all the properties check that if the CurrentCase is one of the AppliedCases of the Model property and if so then use the Razor magic display it accordingly
My question is this correct approach and if so how do I implement it, looking for some examples with dynamic rendering (if that is the name of this topic)
You could use the overload of Html.Editor that takes the name (as string) of the property you want to render:
var fieldNames = new string[] {"LastName"};
foreach (string fieldName in fieldNames) {
#Html.Editor(fieldName)
}
You can use the UIHint attribute in the ViewModel to influence which editor template shall be used:
[UIHint("MySpecialStringEditor")]
public string LastName { get; set; }
At the shop where I work, we do not use this approach. Rather, we use different explicit Views of the same ViewModel. This allows for more flexibility and is easier to understand and maintain.

Is there a nice way to control how display templates should render null fields?

Is there a way to control how built-in display templates (like decimal, string) should render null fields / empty string? I'd want to show "-" as field value for some and empty line for others.
I know I can check those fields for null in the views, but this seems like a not nice thing to do in hundreds of places.
Apply the NullDisplayText property of the DisplayFormat attribute to the relevant view model members.
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "-")]
public string Name { get; set; }
Note, the DisplayFormat attribute is intended to be used with templated helpers such as EditorFor and DisplayFor (which it sounds like you are doing).
You can create your own display template and control the behavior from there.
#model string
#if(Model == null){
// your behavior here.
}
else {
}

Dapper.NET mapping with Data Annotations

So I have a class with a property like this:
public class Foo
{
[Column("GBBRSH")
public static string Gibberish { get; set;}
....
}
For saving data, I have it configured so that the update/insert statements use a custom function:
public static string GetTableColumnName(PropertyInfo property)
{
var type = typeof(ColumnAttribute);
var prop = property.GetCustomAttributes(type, false);
if (propr.Count() > 0)
return ((ColumnAttribute)prop.First()).Name;
return property.Name;
}
This handles fine, but I noticed that when I go to retrieve the data, it isn't actually pulling data back via the function for this particular column. I noticed that the other data present was pulled, but the column in question was the only field with data that didn't retrieve.
1) Is there a way to perhaps use the GetTableColumnName function for the retrieval part of Dapper?
2) Is there a way to force Dapper.NET to throw an exception if a scenario like this happens? I really don't want to have a false sense of security that everything is working as expected when it actually isn't (I get that I'm using mapping that Dapper.NET doesn't use by default, but I do want to set it up in that manner).
edit:
I'm looking in the SqlMapper source of Dapper and found:
private static IEnumerable<T> QueryInternal<T>(params) // my knowledge of generics is limited, but how does this work without a where T : object?
{
...
while (reader.Read())
{
yield return (T)func(reader);
}
...
}
so I learned about two things after finding this. Read up on Func and read up on yield (never used either before). My guess is that I need to pass reader.Read() to another function (that checks against column headers and inserts into objects appropriately) and yield return that?
You could change your select statement to work with aliases like "SELECT [Column("GBBRSH")] AS Gibberish" and provide a mapping between the attribute name and the poco property name.
That way, Dapper would fill the matching properties, since it only requires your POCO's to match the exact name of the column.

How to set default value of TextBox empty string instead of null

I may be out of date, but one principle I adhere to is avoid nulls as much as possible.
However what I have found is that for a strongly typed view in which the user inputs the properties of an object I want to save, if some fields are not entered they are assigned as null.
Then when you try to save the changes, the validation fails.
So rather than set each property to an empty string, how can I automatically set each TextBox on a form to default to an empty string rather than a null?
You could put the following attribute on your string-properties in your model:
[DisplayFormat(ConvertEmptyStringToNull=false)]
So whenever someone posts a form with empty text-fields, these will be an empty string instead of null...
To be honest, I'd say your coding methodology is out of date and flawed. You should handle all possibilities, it's not hard. That's exactly what string.IsNullOrEmpty(value); is for.
I'm guessing your validation logic is something like:
if (value == string.Empty) { isValid = false; }
So it doesn't handle the null values. You should replace that check so it also checks for nulls.
string value1 = null;
string value2 = string.Empty;
string.IsNullOrEmpty(value1); // true
string.IsNullOrEmpty(value2); // true
An alternative solution to using attributes on each model property, as described in the accepted answer, is using a custom model binder, see string.empty converted to null when passing JSON object to MVC Controller
I ran across this problem when dealing with an old service that requires empty strings. I created an extension method:
public static string GetValueOrDefault(this string str)
{
return str ?? String.Empty;
}
So you can use this when you want to make sure any strings that are null become empty
yourString1.GetValueOrDefault();
yourString2.GetValueOrDefault();

How to get model binder to leave null strings as null?

My Sql Server database has some nullable nvarchar fields, and no nvarchar fields containing empty strings. I want to keep it this way, but the default MVC model binder seems to turn null strings into empty strings.
When a controller retrieves a null nvarchar database field, the null field turns into null string inside the controller, and from there the view renders them, say as blank text boxes. When the page is posted, the default model binder uses these blank text boxes to update the model, and the formerly null strings are changed to empty strings. When the data is updated back to the database, nulls are overwritten with empty strings.
What is the easiest way to get model binding to leave these nulls unchanged?
I know you are probably looking for something more sophisticated, but the default behavior of the ModelBinder is to convert empty form field values into the default value for the datatype of your model object property. String properties become empty, int properties become 0, etc.
You can obviously create a validation scheme that will check for string.empty and convert to null prior to updating the DB. For int form fields you will need to check for 0, and then convert to null.
Here's a hack I used a few months ago before I found the eden of stackoverflow. :) It's a pain, and doesn't scale well, but it works:
Basically, you override the binding inside of a partial linq object. If there's a value you know should always be null (but never legitimately empty) you can do the following. I used this for a string-based user id (SID).
partial void OnSubProcess_Owner_UserChanged()
{
if (string.IsNullOrEmpty(this.SubProcess_Owner_User))
this._SubProcess_Owner_User = null;
}
James
The right answer might be to override the default Model binder to add this functionality yourself.
Maybe you could have a NullValueAttribute that you could apply to string properties to identify the null value. Then make empty string a null value.
I am experiencing the same problem at the moment and will probably resort to this
I'm posting this answer to follow through on this question. After working with it for a while I came to see this problem as part of the general concern of model integrity. For a while I had implemented a solution inside my update stored procedures to catch empty strings and turn them to nulls, along the lines of mikerennick's answer above. Later I wanted also to make sure fields were trimmed and I happened to move the application to NHibernate (and most of the stored procedures went away). In the end I embedded some POCO logic to trim and check for empty strings (from whatever source) in the setters as so:
public MyClass {
private string _name;
public string Name {
get { return _name; }
set { _name = value.TrimToNullIfEmpty(); }
}
}
public static class StringExtensions {
public static string TrimToNullIfEmpty(this string s) {
string temp = (s ?? "").Trim();
return temp.Length == 0 ? null : temp;
}
}

Resources