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.
Related
I have a part of my application which querys a database for records. One of the fields in this query is a string type status of known values:
Open, Closed, Cancel
The user has 3 check boxes and can select any combination to determine which types of records they get back. So in my view model I have a status filter property with 3 bools:
public class SalesOrderStatusFilter
{
public bool Open { get; set; }
public bool Closed { get; set; }
public bool Canceled { get; set; }
}
Now when a query is run, I'd like to filter the results based on the chosen status types. Right now I've got a linq query like this:
public IEnumerable<SalesOrders> GetSalesOrders(SalesOrderParams parameters)
{
return _dbContext.SalesOrderLookup()
.Where(x => (x.Status.EqualsTrim("Open") && parameters.SalesOrderStatusFilter.Open)
|| (x.Status.EqualsTrim("Closed") && parameters.SalesOrderStatusFilter.Closed)
|| (x.Status.EqualsTrim("Cancel") && parameters.SalesOrderStatusFilter.Canceled)).ToList();
}
This is a common pattern across my application and I'd like to find a better solution that I can reuse without having to keep typing out the query every time. I've already tested out converting my db string statuses to enums using some custom attributes, reflection, etc, but I'm worried it's a bit overkill when I'm doing mostly view-only type querys for these various reports, so I'm not sure I'm going to stick with it. It's also added a bit of a performance hit to do the enum conversion (The enum values didn't always match the database values, so thats why I was using reflection and custom attributes).
Can anybody recommend a good approach to dealing with this problem?
Edit:
for clarity, the SalesOrderStatusFilter is a property of another
public class SalesOrderParams
{
public string SalesOrderNumber { get; set; }
public SalesOrderStatusFilter SalesOrderStatusFilter { get; set; }
}
I think the main challenge I'm trying to solve is mapping the bools to their string equivalents, which may not always match by name (sometimes theres a space, for example), and then making a more concise and reusable call.
Please try like this
First compare with status again compare with parameters status... (&& replace for ==)
_dbContext.SalesOrderLookup()
.Where(x => (x.Status.EqualsTrim("Open") == parameters.Open)
|| (x.Status.EqualsTrim("Closed") == parameters.Closed)
|| (x.Status.EqualsTrim("Cancel") == parameters.Canceled)).ToList();
Why you don't use bool type? Even if you use enums and define it as byte type, it takes 1-byte length for each record while using 3 bool type, takes 3-bit length. Also the performance of checking one bit is higher than comparing a string. So I think better choice for you is defining three bool type for status variables as you define check boxes. Also in this way you will be able to read from and writ to db directly without any data conversion.
I have a SQL query that looks like
SELECT CONVERT(BIGINT, MY_TABLE_FIELD)
FROM SOME_TABLE
WHERE [CONDITIONS]
I need to cast the string MY_TABLE_FIELD to a long value field in Linq.
I've tried with long.tryParse, (long)MY_TABLE_FIELD, and Convert.ToInt64(MY_TABLE_FIELD) inside the select clause in the Linq expression.
I have read about methods that converts value, but i get error. And I don't want to use lambda expressions.
What can I do?
Supposing your values are actually convertible to longs, you should be able to do this:
from context.SOME_TABLE
where ...
select Convert.ToInt64(row.MY_TABLE_FIELD)
If the values are not convertible to longs, you might want to consider selecting out the string from the database, and then post-processing the values based on more complex business logic.
(If this doesn't work, provide the error message that you're getting, and more details on your database, etc.)
Thanks StriplingWarrior for your answer.
I´ve found a solutions few minutes after i posted the question.
Here I share it.
LINQ
var MyList = (from ta in model.Table
select new MyClass
{
StringFieldID = ta.StringFieldID,
OtherField = ta.OtherField
}).ToList();
And the work i did it on the class MyClass Code
public class MyClass
{
private string _StringFieldID;
public long LongFieldID { set; get; }
public string OtherField{set;get;}
public string StringFieldID{
set
{
_StringFieldID= value;
LongFieldID= long.Parse(_StringFieldID);
}
get
{
return _StringFieldID;
}
}
}
So, every time the Linq Query sets a value for StringFieldID is the class who makes the casting.
Let's say we have a class that has an int array as one of its properties.
public MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public int[] Values { get; set; }
}
We store it in the db using entity framework. What I've noticed is that EF turns the Values property into a varchar(max).
Now, what we would want to do, is to query the database and return records for which 'Values' contains the given int parameter.
public List<MyClass> Search(int valueToSearch)
{
return context.MyClasses.Where(x => x.Values.Contains(valueToSearch)).ToList();
}
However, this throws an exception that linq-to-sql does not support the contains command.
I also tried Where(x => x.Values.Any(y => y == valueToSearch)) but that throws the same exception.
I suppose it has something to do with the fact that EF turns the array into a varchar so it won't be able to use the contains statement or something. Maybe a seperate table for the Values would solve the problem, but it looks kinda stupid to create a class that only has one integer property?
Is there a better way to solve this?
I found a lot of examples doing the opposite (the SQL IN statement) but that's not what we're looking for. We only have one integer as parameter, but several integers in our entity.
We're using EF5 with .NET 4.0.
Thanks!
Edit
It seems the varchar is a string we create ourselves. As it was code I didn't write myself, I wasn't aware of that. That string ofcourse gets translated into a varchar.
So now the question changes into something like 'What's the best way to store arrays of primitive types?' and that question has already been answered many times here on SO (one of them is provided in the comments).
Do the query outside of linq to entities: (you have to pull in all the rows)
public List<MyClass> Search(int valueToSearch)
{
var c = context.MyClasses.ToList(); // cache
return c.Where(x => x.Values.Contains(valueToSearch));
}
EDIT: If you are currently manually converting the array of integers into a string, then change your class property from an array of integers to a string.
Although, I recommend a new table. An array of integers as a string in a db fields smells a little.
The error I get is this:
The 'SalesValue' property on 'ItemSale' could not be set to a 'Decimal' value.
You must set this property to a non-null value of type 'Single'.
But I already did:
[Table("ItemSales")]
public class ItemSale {
[Key]
public int ID { get; set; }
....
public Single SalesValue { get; set; }
}
Here is my LINQ, simple enough:
from x in database.ItemSales
select x
I am using Entity-Framework Code First
How do I solve this?
Have you checked the precision of the column type ? That was an error i once came along which, as far as i remember, was very similar to yours.
As far as i remember, the precision had to be 2, but had another value.
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.