Linq To Sql: Exception "String must be exactly one character long" - c#

Consider a SQL Server table defined with a varchar(1) NULL field. It's being used to store a gender character. Some rows have data, some not: either null or blank. Granted the blanks SHOULD be nulls, but consider that blank is a valid value here. I'd much prefer the value to be null.
ID Gender
1 'M'
4 'M'
3 ''
4 'F'
An exception is raised when running a Linq To Sql query where the value of someID is 3.
var emp = (from e in db.Employees
where e.ID == someID
select e);
Exception:
String must be exactly one character long.
Question: What is the cause of this exception? What can be done to prevent or eliminate this problem?

Check the Employee type that was created for you by the LINQ to SQL designer. Most likely the type for the Gender property is System.Char (which is the type that the LINQ to SQL designer uses for varchar(1)) and should be changed to a System.String to properly match your database schema.
The fact that the LINQ to SQL designer interprets a varchar(1) as a System.Char is foolish considering that this is valid T-SQL:
declare #foo varchar(1);
set #foo = '';
and this is invalid C#:
Char foo = '';
Since the type of the property that was generated is too restrictive you need to change it to be a System.String.
Note: You may want to consider adding some validation inside the setter of the property to throw an exception if the length of the string is greater than one.

Is it possible that the blank data like '' doesn't meet the current constraints of the table? E.g. perhaps the table doesn't permit empty strings (even though there is one in there).
Then, maybe LINQ is applying those constraints for you, or expecting those constraints to be met and complaining that they are not.
If this is what is going on, you might change the constraints/design of the table to allow blank values, or just update all the blank values to NULL (assuming NULLs are allowed)

This problem also occurs when Linq To SQL Designer tries to auto generate a results class, for holding stored procedure results. Copy the auto generated class into your own new class file (use same name) and make changes there. Each time you update your DataContext it will just be a case of deleting the auto generated class. Not an ideal solution but a workaround for 2008.

Related

LINQ query returns error "The expected type was 'System.Int32' but the actual value was null."

So this is the query:
from c in Contents
join cs in DepartmentSharings
on c.ContentId equals cs.ContentId
select c.PrivateCategoryId.Value
When I run this I get:
A database operation failed while processing the request.
InvalidOperationException: An exception occurred while reading a
database value for property 'DepartmentSharing.ContentId'. The
expected type was 'System.Int32' but the actual value was null.
Now I checked the DepartmentSharings.ContentId field in the database, its fk, int, not null. In the class it's public int ContentId { get; set; }. DepartmentSharing.ContentId cannot be null. Also, in LinqPad I can see it returns 58 rows before failing.
Why am I getting this error?
The only thing that will cause that error is if ContentId is a non-nullable int property, but somehow your database table is allowing NULL values for that column. Assuming EF is handling your database, that shouldn't happen, but it's possible you've changed something at some point and didn't migrate properly.
Regardless, you need to either change the property type to int? instead of int or alter the table to make the column NOT NULL and ensure all the rows have a non-NULL value.
Chris's answer looks sensible and correct but I have another experience.
I have two tables, they are related. The field with problem is match (not a key but like a key) field. Property is set non-nullable and related database field is same too. The problem occured because of there was no any related data with first table in second table. So, comparing two fields was causing problem. Actually this case is not expected but test data was corrupted. Even so, I added another condition before existing condition as "if data exists" and problem is gone.

Entity Framework Error when no records are returned

.Net Framework 4 | SQL Server 2008 | Entity Framework 6
I am calling a function import that calls a stored procedure and creates a complex object. In some cases the result is 0 records. It seems that if you have this case all the columns in the complex object must be set to allow nulls. I don't want to do that because, if there were records, non of the columns would be null. This is causing me to have to check for nulls on all of these fields instead of just checking if the returned list has any rows.
Am I doing something wrong or is that just the way EF is set up?
UPDATE:
I'm not really sure what code you want. It's a simple SELECT statement. The stored procedure call is through a regular Function Import. Here's how I am calling that:
// Get the district entity
List<SchoolCollectionSummary_Result> summaries =
context.GetSchoolCollectionSummary(
schoolYear.SchoolYearId, districtOrganizationId,
schoolOrganizationId).ToList();
SchoolCollectionSummary_Result is a complex type (entity) based on the stored procedure.
As soon as I enumerate it the error occurs:
{"The 'SchoolCollectionId' property on 'SchoolCollectionSummary_Result' could not be set to a 'null' value. You must set this property to a non-null value of type 'System.Int32'. "}
I set all the fields "allow null = false" because the database fields are set to NOT NULL.
Thanks.
UPDATE
Thanks for asking for the SQL. When looking through it I noticed there's a LEFT JOIN which was the cause of my problems...

Linq to SQL: Load default field Values ONLY for fields with NULL value

I'm using Linq-to-SQL for a table which got records named Category and Record has a column which named Level which its default value defined -1 through Database declarations.
I want my C# application act like this for Inserting new record R of type Category:
if field Level of Variable R is null:use default DB values for
insertion
if filed Level of Variable R is defined (NOT NULL):use value of
this field for insertion
I have used Auto Generated property for field Level but it will cause using default Values for all cases of insertion.
Linq2SQL does not support SQL Default values at all, so there isn't any "built-in" way to do this.
However you could always go and find out the default value of the column in SQL:
select DefaultValue=Column_default from from information_schema.columns where column_name='Level' and table_name='Category'
You could execute that command on app startup and store the value (converted to the correct type of course) for later use:
if (newCategoryToInsert.level==0)
{
newCategoryToInsert.level = levelDefaultValueThatIStoredEarlier;
}
dbContext.SubmitChanges();
and use that in Dan's approach.
But if possible, don't bother with any of this and just accept that NULL is a good default value for an undefined Level, change the schema to allow NULL for "Level" and refresh your DBML, then you just don't have to worry about it any more.
This sort of structure should work.
if (R.Level == null)
linq query that does not include R.Level. Database will apply default value
else
linq query that includes R.Level

Send a empty DateTime value into SQL stored procedure. But not null

I have an SQL stored procedure which accepts a DateTime parameter which has a default value of NULL
#pmNext_Check_Date DATETIME=NULL
I want to use this parameter in 3 scenarios:
If it's NULL then don't update any records
If it's got a date value then update all my records specified in my WHERE clause
The problem one! Set all the date fields in my query to NULL for the records in my WHERE clause.
Here is the block of code within the SP that is causing me issues (the rest of the UPDATE statement is build elsewhere in the SP and works fine):
IF #pmNext_Check_Date IS NOT NULL
IF #pmNext_Check_Date ='' --This is the bit that is causing me a problem. I just need to check for a empty date
SET #sql = #sql + ' Next_Check_Date = NULL '
ELSE
SET #sql = #sql + ' Next_Check_Date = #pmNext_Check_Date '
SET #sql = #sql + ' WHERE ID IN (1, 2)'
So for example if I have the following 2 rows:
ID NextCheckDate
1 12/12/12
2 NULL
In scenario 1 I wouldn't pass the parameter in as the procedure will use the default value and no dates will be updated.
In scenario 2 I pass in a date value and update both rows with the date value
In scenario 3 I want to update the date value on my rows to be null. The difference between scenario 1 & 3 is in scenario 3 the user will be choosing to set the date values to null.
So, I wanted to pass a blank date into the stored procedure. I'm doing this from C# and would like to do something like the following:
SqlParameter param = new SqlParameter("#pmNext_Check_Date", "");
This fails as the SP is expecting a DateTime.
So I want to be able to pass in a blank date and also how do I check this within the SP. The current check which is below doesn't work:
IF #pmNext_Check_Date =''
Thanks in advance.
Hope this all makes sense.
I'm using C#4.0 and SQL 2008
There is no such thing as a "blank date". You could use a well-known sentinel value (01 Jan for some arbitrary ancient year, for example), but null would be preferable. Note that to pass an explicit null via a parameter, you need:
SqlParameter param = new SqlParameter("#pmNext_Check_Date", DBNull.Value);
If that doesn't have enough granularity, consider adding a separate boolean (bit) parameter (or similar) that clarifies what you want the sproc to do. Or: have multiple procs to do these different things.
One useful sentinel value for SQL Server is January 1, 1753 (SQL Server's minimum datetime value) - this can be produced in TSQL without string parsing as cast(-53690 as datetime).
You can't pass an empty string as a datetime. So, you have a couple options. You could add an additional parameter to indicate whether or not an update should occur. I suggest that as the best options for code readability and maintainability. The other option would be to pass in the parameter as a string and parse it. That way you could use your empty string concept.
Sql Server string to date conversion
Sorry, there is no way to do precisely what you're asking. A DATETIME value is either NULL or a valid date, there is no "empty" like there is with strings.
Another workaround is to pass a token value (that wouldn't be a valid date otherwise) to represent your so-called empty string, e.g. a common one I've seen used is 1900-01-01. Then you can differentiate in your stored procedure between NULL and "empty."
But I don't recommend doing this at all. I agree with the other suggestions: add another parameter and do the logic in a more meaningful way in the stored procedure.
If I can recall correctly, columns with a DATETIME datatype which allow NULLS
will default to the value 1900-01-01 instead of a BLANK value.
For example:
NULLS may be allowed for certain columns which might receive a value later down the line based on some kind of business logic. I have seen folks keep these open ended columns as varchar to enable a custom entry of some type or an empty string, something which datetime will not allow.
If you ask me I'd try not to mess around with the base column's data type and let it remain as DATETIME. For data retrieval and reporting purposes we might try the following approach, which may not be the best way to do it. But it works.
BEGIN
DECLARE #VarcharDateTable TABLE
([EndDate_Varchar] varchar(27))
BEGIN
INSERT INTO #VarcharDateTable([EndDate_Varchar])
SELECT
CONVERT(varchar(27), [EndDate_Datetime], 121)
FROM [dbo].[MainTable]
END
BEGIN
SELECT CASE WHEN [EndDate_Varchar] LIKE '1900-01-01%'
THEN 'Data unavailable'--or whatever you want
ELSE [EndDate_Varchar]
END AS [EndDate_Varchar] FROM #VarcharDateTable
END
END

c# Access inserting new data to table with autonumber

I have a table with these columns:
PersonID AutoNumber PrimaryKey
TCKimlikNo Number
PersonName Text
PersonSurname Text
Address Text
Birthdate Text
CategoryID Number
When im trying to insert value from c# I am using this query:
INSERT INTO Person(TCKimlikNo, PersonName, PersonSurname, Adress, BirthDate, CategoryID)
VALUES(#tcKimlikNo, #personName, #personSurname, #adress, #birthDate, #categoryId)
But it says:
"Microsoft Access set 1
field to Null due to type conversion
failure, and it didn't add 0 record(s)
to the table due to key violations, 0
record(s) due to lock violations, and
0 record(s) due to validation rule
violations."
I think the error occuring because of that autonumber column. Access trying to insert null value to that, but field wont let it. In SQL this query works perfectly. But Access is just annoying.
The NULL value is because of a type conversion issue. Most likely you are passing data into one of your fields that cannot be converted by Access into the data type that it is expecting. I would guess that you are passing in a value to CategoryID that is not converting to a proper number. This could also be true of the TCKimlinkNo field. I believe if the string field is too short for the passed-in values, it will just truncate them so I doubt this is the issue.
Also, don't forget to check the size of your number fields. Is the number you are entering larger than the number allowed? Are you sending decimal data when it is expecting a whole number?
The autonumber won't be a problem unless you are trying to write to it (which you don't appear to be doing.

Categories