Nullable string property/column in nHibernate + Fluent - c#

I'm new to nHibernate universe, so this question can be idiot ..
I have a table with a nullable nvarchar column.
In the mapping i use this Map(c => c.Genero, "genero").Nullable();
In the property i use trim to set the value, so i have a private string and a public virtual string.
When i do an select in this table i receive an runtime error in the setter of this property.
I tryed to pass this property to Nullable, but i receive a compile-time error saying The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'.
How can i do this ?
Thanks for everyone !
UPDATE
If i use just the property with { get; set; } works normally, but i need to trim.

The problem may be that you can't trim a null string. Try:
public string Genero
{
get { return _genero; }
set { _genero = string.IsNullOrEmpty(value) ? value : value.Trim(); }
}
Depending on your mapping, this may cause the trimmed string to be written to the database when the session is flushed. It might be better to map the string as a private field and trim it in the getter.

Related

New c# nullable option

In new version of C# is default option nullable. I mean this
It's really good feature for me. But I don't understand one thing. Is property nullable by me or by program?
I know that this property should never be null because I fill it in the form and never set it as null. But in general it can be null. How should I mark it?
Example:
UserModel:
public string? Name { get; set; }
public string Name { get; set; } = null!
I'm really confused.
I know that this property should never be null because I fill it in
the form and never set it as null. But in general it can be null. How
should I mark it?
If it is set to non-null in the constructor, then you can declare it a string rather than string? because it really is guaranteed to never be null.
If, however, it is null after the constructor has run (and before any other methods are called) then it CAN be null and you should declare it as string?.
The dichotomy you face is that (from what you say) it should never be null when the class is used correctly - i.e. if the calling code does indeed call the method that initialises the property to non-null before accessing it, it will be guaranteed to be not null - which means you would like to declare it as a non-null string so that callers don't need to use the null-forgiving ! operator to suppress nullable warnings.
What to do in this case? Well I think you have three possibilities:
Declare the property as nullable: string? and let the callers suppress the nullable warning or check the value for null.
Initialise the property to a non-null default such as string.Empty and declare the property as non nullable string.
Assume that accessing the property when it is null is a programming error, and throw an appropriate exception.
For the last case, you could do something like this:
private string? _name;
public string Name
{
get
{
if (_name == null)
throw new InvalidOperationException("Do not access Name without setting it to non-null or calling Init()");
return _name;
}
set
{
if (value == null)
throw new ArgumentNullException("value", "You cannot set Name to null.");
_name = value;
}
}
This assumes that there's a method called Init() that can be called to initialise Name, but of course your code may vary.
Regardless of which of those approaches you take, you should really check for null in the property setter, as shown above.
Note that a more succinct way of writing the setter null check is:
set
{
_name = value ?? throw new ArgumentNullException("value", "You cannot set Name to null.");
}
Where a value can be null, and the <Nullable>enable</Nullable> value is set in your *.csproj file, you must declare those values as nullable.
In your given example, the nullable type (instead of assigning null as a default) is the way to go:
public string? Name {get; set;}
You'll also notice VS complaining at you with warnings every time you introduce a property etc which can be nullable, but isn't marked as such.

Filehelper differenciate errors based on Exception Message and manipulate record string

I am using the FileHelpers library for identifying errors in processing csv file.
var engine = new DelimitedFileEngine<ModelClass>;
engine.ErrorManager.ErrorMode = ErrorMode.SaveAndContinue;
List<object> fileEngineResult = engine.ReadFile(fullFileName).ToList();
errorInfo = engine.ErrorManager.Errors;
My ModelClass has the properties corresponding to each column in my csv file with validation attributes
[DelimitedRecord(",")]
[IgnoreEmptyLines]
public class ModelClass
{
[FieldNotEmpty]
private string column1;
[FieldConverter(ConverterKind.Date, "MM/dd/yyyy")]
private DateTime datecolumn;
[FieldNotEmpty]
private string column3;
}
Now for me any error in the field not empty is critical hence I will have to deal with seperately.
For a non critical error, in this case datecolumn, I need to replace wrong value with null.
I could achieve my 1st requirement using the below code( it is still a crude way)
List<object> criticalErrorList = new List<object>();
List<object> softErrorList = new List<object>();
foreach (var error in errorInfo)
{
if (error.ExceptionInfo.InnerException.ToString().Contains("The value is empty and must be populated"))
{
criticalErrorList.Add(error);
}
else
{ error.RecordString = //replace recordstring for the error column with null;
softErrorList.Add(error);
}
}
}
Any idea to achieve 2nd requirement?
Reading your question more carefully I see that want you really want is to get a null value when there is an error in your datecolum field.
I wrote this answer first and I'll let it here because I think you can benefit from it too. Maybe you could get a null value if field is missing and also get a null value if field data is wrong.
Initial answer (handling missing values with nullable types.)
Fortunately you don't need to change the record string (it's readonly), but you use something built-in in FileHelpers to achieve that. Change your model so the date column is a nullable DateTime.
[FieldConverter(ConverterKind.Date, "MM/dd/yyyy")]
private DateTime? datecolumn;
Another approach is if you would want to have a default value for the date column. Then you could use another attribute to decorate the datecolumn member:
[FieldNullValue(typeof(DateTime), "01/01/1900")]
[FieldConverter(ConverterKind.Date, "MM/dd/yyyy")]
private DateTime datecolumn;
Updated answer:
Get null value when data is wrong
Converters:
This is another feature of FileHelpers. You can read more about it here:
So, let say you need to get a null value if the data is wrong for date column. You'll still need to change your datecolumn field to DateTime? but also you'll need a converter.
public class DateConverter : ConverterBase
{
public override object StringToField(string from)
{
//if you can't convert to date time.. .return null
DateTime date;
if (!DateTime.TryParse(from, out date))
return null;
return date;
}
public override string FieldToString(object fieldValue)
{
return ((DateTime) fieldValue).ToString("MM-dd-yyyy").Replace(".", "");
}
}
And in your model class, decorate the field with the converter:
[FieldConverter(typeof(DateConverter))]
public DateTime? datecolumn;
Now you'll get no erros when reading the file and if the date field is wrong in the file, you'll get a null value in the model class.
Hope this helps!

Can Dapper handle nullable boolean/bit fields? [INVALID]

I'm trying to use Dapper for the first time, but I've immediately run into the problem in that it doesn't seem that Dapper can handle nullable fields. This surprises me greatly as these are extremely common.
If I have a nullable boolean field in my SQL Server database and try and use Dapper to populate the nullable boolean property on my C# class, an exception is thrown if the boolean field contains a null value:
System.FormatException: String was not recognized as a valid Boolean.
Is there any fix or workaround for this? I find it hard to believe Dapper can't handle this as it looks like it's been around for a while and this is an extremely basic function.
EDIT: This was my mistake! My column was actually a nvarchar which happened to contain 0 or 1, and as such, I hadn't noticed. Changing it to BIT (or the C# property to "string?") fixes the problem.
Yep, works just fine:
public void SO24607639_NullableBools()
{
var obj = connection.Query<HazBools>(
#"declare #vals table (A bit null, B bit null, C bit null);
insert #vals (A,B,C) values (1,0,null);
select * from #vals").Single();
obj.IsNotNull();
obj.A.Value.IsEqualTo(true);
obj.B.Value.IsEqualTo(false);
obj.C.IsNull();
}
class HazBools
{
public bool? A { get; set; }
public bool? B { get; set; }
public bool? C { get; set; }
}
Since Dapper does not make too much plumbing, the recordset coming from the database contains a string, a stated by the error. Try to check the column type, and when it is clear you can change the DTO class accordingly, or cast it in some way in the query.

Non-nullable property is null

I have a very simple class Address:
public class Address
{
public string Name { get; set; }
public string Country { get; set; }
}
I declared Name as string and NOT as string?, because it should never be null.
Now i have a method where i get an instance of this class as parameter:
public List<Address> SearchAddress(Address search)
{
...
if (!search.Name.Equals(string.Empty))
{
temp = query.Where(a => a.Name.Contains(search.Name));
}
...
}
Now my colleague called this method and i got a System.ArgumentNullException because search.Name is null.
If i have a non-nullable int property i get 0 as value if i don't assign anythig to it.
Why is a non-nullable string property null if no value is assigned and not just string.Empty?
int is a non-nullable value type (i.e., a struct). Value type fields will be initialized to their default value. E.g., int to 0, bool to false, etc. Full list here.
When you want to be able to assign null to value type variables, you can use Nullable<T> where T : struct or, in the case of an int, Nullable<int>/int?.
string, on the other hand, is a reference type. Reference types can be null, and reference type fields will be initialized as null. As such, having a Nullable<string>/string? is not allowed nor would it make sense.
In your case, you'll want to check whether the Name string is null or empty
if (! String.IsNullOrEmpty(search.Name)) { ... }
String can hold null values, its simple as that!
String is a reference type, but is has certain behavior of value type.
Please read this topic : Null strings and empty strings
You can use the string.IsNullOrEmpty to determine a instance if it is Null and empty string .
string is a reference type and it's null by default. String.empty is equivalent to a double quoted empty string ("") and hence null is not the same as String.empty.

What does it mean when it says 'int' is never equal to 'null' of type 'int?' [duplicate]

This question already has answers here:
Why type "int" is never equal to 'null'?
(8 answers)
Closed 9 years ago.
I am trying to compare the following:
if (e.CreatedBy == null)
But this is giving me an error saying:
The result of the expression is always 'false' since a value of type
'int' is never equal to 'null' of type 'int?'
Can someone help tell me how I can check if the value of CreatedBy has not been set yet? Note here's the definition of CreatedBy:
public int CreatedBy { get; set; }
int is a value type which means it can never be null. Its default value is 0. If you want store null instead of 0, you need to change the type to int?, which is a nullable int type. To read more about Nullable types, check "Nullable Types (C#)"
The type of CreatedBy is int which is a type that cannot take the value null.
From what you currently have, it is not possible to detect whether or not CreatedBy has been set. Suppose that its default value is 0. Then the value is set to 1, and then back to 0. Now, how can you distinguish the current 0 from the original unmodified 0?
If what you want to do is detect whether or not the value is 0, well I don't think I need to tell you how to do that. If you really want to detect whether or not the value has ever been set you'll need to maintain a bool flag and set that flag the first time the property's setter executes.
The int value is a type of non Nullable types see
http://msdn.microsoft.com/en-us/library/1t3y8s4s(v=vs.80).aspx
if you want to check if set or not use
//GetValueOrDefault()
private int? createdBy;
public int CreatedBy
{
get { return createdBy.GetValueOrDefault(-1); }
set { createdBy= value; }
}
///your code
if(e.CreatedBy == -1)
{
//not set
}else
{
//set
}
int is a value type which can't be null. If you want to make a value type nullable, you need to use int? which is a shorthand way of creating a Nullable object like this
Nullable<int> myNullable = new Nullable<int>();
Can someone help tell me how I can check if the value of CreatedBy has not been set yet?
No, that is impossible since value types (like int) can't be null.
But you can use Nullable Types which let's you declare it as a "Nullable of int" and then it can be null.
From the documentation I linked to:
A nullable type can represent the correct range of values for its underlying value type, plus an additional null value
To make your property a "Nullable of int", just add a questionmark:
public int? CreatedBy { get; set; }
The above syntax is actually just a shorthand for:
public Nullable<int> CreatedBy { get; set; }
Because default value of int is 0 not null. e.CreatedBy never going to have the value like null so better is to compare it with 0.
if (e.CreatedBy == 0)
nullable int can be equal to null but not nullable (default int) never going to be equal of null.
Well you are using int not nullable int so it can't be null ever?
You could change the definition of your CreatedBy as follows:
public int? CreatedBy { get; set; }
and they you can make the following check
if (e.CreatedBy == null) or if (e.CreatedBy.HasValue)
Ok, lot's of answers explaining the obvious. Here's a couple of ideas for actually solving your problem:
One alternative: Just use the default value 0.
Now, instead of checking for null in your original code, you can check if(CreatedBy > 0).
If you prefer to be more "explicit", you could use -1 to explicitly indicate "empty" or "not set", by setting it as a default value in the constructor. I'm not saying this is ideal in all situations, but it is fairly simple:
public YourClass(){
CreatedBy = -1;
}
public int CreatedBy { get; set; }
Obviously, this leads to the test: if(CreatedBy != -1).
Another alternative is to use nullable of int, as some have sugested, and check for null. This has the downside of having to deal with the type int? instead of the more "general" int everywhere you work with that value though. That may not be a problem, but sometimes it can get annoying, especially if you pass the value to other methods, classes, or whatever..
To answer your question, you can't check whether the value has been set, you can only check what value it has now. Any property will have a 'default' value when it's initialised. For most types (including Nullable), the default value is null, however for int the default value is 0.
If you're sure that nobody would ever set this property to 0 for any other reason, then you can test for:
if (e.CreatedBy == 0)
...however, if 0 is a valid value for this property under another circumstance, then testing for 0 won't help you. Equally, it you change the property to nullable, then you can test for:
if (e.CreatedBy == null)
...as per your original design, but if there is any other reason why the property might be set to null then again you're not finding out if it had ever been set, only that the last time it was set, it was set to null.
If you want to really know whether the value has been set, you need to arrange for something else to happen when the setter is used, for example to set another flag. Here's an example of doing exactly this, where the CreatedByHasBeenSet property is false (the default value of bool!) until the setter on CreatedBy is called:
private int createdBy;
public int CreatedBy
{
get
{
return this.createdBy;
}
set
{
this.createdBy = value;
this.CreatedByHasBeenSet = true;
}
}
public bool CreatedByHasBeenSet { get; private set; }

Categories