I am trying to insert a DateTime value in sqlserver using linq. The DateTime value in the csharp side may be null. The corresponding field in sqlserver is a nullable datetime field. Following is my code:
using (var dataContext = GetDataContext())
{
DateTime dateTime;
var combinedWorkBasket = new CombinedWorkBasket()
{
FirstName = combinedWorkbasketData.FirstName,
LastName = combinedWorkbasketData.LastName,
Address1 = combinedWorkbasketData.Address1,
RetirementDate = Convert.ToDateTime(combinedWorkbasketData.RetirementDate),
};
dataContext.CombinedWorkBaskets.InsertOnSubmit(combinedWorkBasket);
dataContext.SubmitChanges();
}
When combinedWorkbasketData.RetirementDate happens to be null, which is a string value, which could be a valid date or null, then sqlserver throws error saying the date should be within range. When combinedWorkbasketData.RetirementDate happens to be null, Convert.ToDateTime(combinedWorkbasketData.RetirementDate) translates to some invalide data value. I tried the following, still same issue.
RetirementDate = DateTime.TryParse(combinedWorkbasketData.RetirementDate, out temp) ? Convert.ToDateTime(combinedWorkbasketData.RetirementDate) : Convert.ToDateTime(null)
I simply want to accomplish the following: When combinedWorkbasketData.RetirementDate is a valid date insert RetirementDate, otherwise don't insert it but insert other values such as Firstname etc
Thanks
You might want to use a nullable data type, but this helps only if your database permits null values in the RetirementDate column. In addition, you must make the RetirementDate field in class CombinedWorkBasket nullable, too.
using (var dataContext = GetDataContext())
{
DateTime? dateTime;
var combinedWorkBasket = new CombinedWorkBasket()
{
FirstName = combinedWorkbasketData.FirstName,
LastName = combinedWorkbasketData.LastName,
Address1 = combinedWorkbasketData.Address1,
RetirementDate = combinedWorkbasketData.RetirementDate != null ?
Convert.ToDateTime(combinedWorkbasketData.RetirementDate) : null;
};
dataContext.CombinedWorkBaskets.InsertOnSubmit(combinedWorkBasket);
dataContext.SubmitChanges();
}
The problem is that datetime does not holds null value but it holds minimum time i.e. some thing like this. '1/1/0001 12:00:00 AM'.
Instead of directly passing the date time try using
DateTime.MinValue== Convert.ToDateTime(combinedWorkbasketData.RetirementDate)?Null:Convert.ToDateTime(combinedWorkbasketData.RetirementDate)
I have not tested the code use it as reference u might be needing some refinement.
I think RetirementDate must be of nullable type for Entity framework to insert DBNull.
So make it like
public class CombinedWorkBasket
{
// other fields
public DateTime? RetirementDate { get; set; }
}
Then try assigning Null as per logic with associated column as "Allow Null" in database.
Hopefully it will insert null.
Related
We have a notmapped conversion field with a kendo control bound to it. When we delete all entries from the control, it posts a null to the controller.
The created model is not running the setter for that field, according to the breakpoints I set in it.
Here's the two fields in question:
[NotMapped]
[Display(Name="Execute Time(s)")]
[DCRequired]
public IList<int> ExecuteTimes {
get
{
return ExecuteHourUTC?.Split(',').Select(s => GetUtcHour(s)).ToList();
}
set
{
if (value != null)
{
// Special code here to ensure the times are numerically in order by local time
// and saved that way for viewing on next load or in the grid.
var values = value.ToList() // convert to List to be sortable/linqable
.OrderBy(x => x) // sort numerically so they are stored in chronological order
.Select(x => new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, x, 0, 0)) // use the integer value to create a DateTime
.Select(d => Core.DateHelper.ToUTC(d, UserTimeZone).Hour); // convert the generated DateTime into a UTC DateTime and return the Hour value
ExecuteHourUTC = string.Join(",", values); // join these Hour (int) values as a CSV
}
}
}
[Display(Name="Execute Times")]
public string ExecuteHourUTC { get; set; }
execute hour utc is bound to the database.
Note: I fixed the problem this was causing (it was leaving the old values in the db field) by bind excluding the db field from the post. I just want to know what the actual reason I'm having this issue is.
I also tried changing the datatype to iList<int?>. That didn't help.
I am getting a System.InvalidCastException at runtime with this code:
inf.Country = (Country)(int)rdr["Country"];
Model class:
public class BasicInfo
{
.....
public Gender Gender { get; set; }
public Country Country { get; set; }
}
public enum Gender
{
Male,
Female
}
public enum Country
{
Australia,
Bangladesh,
England,
France,
Usa
}
DbConnect class: the method return the entities list and it will pass through the controller's view.
usp_GetAllStudentData is a stored procedure that returns the list of records.
public List<BasicInfo> SelectStudent()
{
ConnectionString();//Contain Connection string
List<BasicInfo> entities = new List<BasicInfo>();
SqlCommand cmd = new SqlCommand("usp_GetAllStudentData", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while(rdr.Read())
{
BasicInfo inf = new BasicInfo();
inf.FirstName = (string)rdr["FirstName"];
.....//other required value are assigned to class members.
//inf.Gender = (Gender)(int)rdr["Gender"];
inf.Country = (Country)(int)rdr["Country"]; // Getting run time exception here
entities.Add(inf);
}
return entities;
}
How the data is stored in the database
Can you guys let me know what is the best method to cast an enum value?
Or let me know if there is any alternative way to fix this issue.
Table Design
If your database field contains a NULL value then the result of your code is the Invalid Cast Exception
For example
object x = DbNull.Value; // A null value on the db is represented by DbNull.Value
inf.Country = (Country)(int)x; // Gives the Invalid Cast Exception
How to fix depends on what you want to do with null values. If you don't allow null values for countries then you should revise your code that accepts an invalid input and block these inputs (and not forget to set the Country field to NOT allow NULL values on the database table)
If you accept a null value then I suggest to add another entry to your country enum
public enum Country
{
Australia = 0,
Bangladesh,
England,
France,
Usa,
// <=== new countries should be added here....
Undefined = 9999
}
and change your reading code to
int ordinal = rdr.GetOrdinal("Country");
inf.Country = rdr.IsDBNull(ordinal) ? Country.Undefined
: (Country)(int)rdr["Country"];
From your comments it seems that you have stored the numeric value of the enum in a varchar column transforming your number in a string
If you want to convert back this string to the appropriate enum value then you should use Enum.TryParse, but the conversion back is not as simple as it seems.
So if you want to still check for null values then:
int ordinal = rdr.GetOrdinal("Country");
// Check for null value....
if(rdr.IsDBNull(ordinal))
inf.Country = Country.Undefined;
else
{
// OK, not null, but what if it is "ABC"??
if(!Enum.TryParse(rdr["Country"].ToString(), out inf.Country))
inf.Country = Country.Undefined;
// OK, but what if it is a number not defined in the coutry enum (IE "88")
if(!Enum.IsDefined(typeof(Country), inf.Country))
inf.Country = Country.Undefined;
}
As you can see, if there isn't a specific reason then I suggest to store the enum value as an integer and not as a string. This allow more flexibility in your code and in future changes to this variable.
try this
if (rdr["Country"]!=DBNull.Value)
{
inf.Country =(Country)Enum.ToObject(typeof(Country) , rdr["Country"].ToString());
}
Is where a way to check if DateTime is null in linq expression? I've IEnumeable method where I'm returning data from database
return _requestRepository.ExecuteProcReader(
myRequest,
new SqlParameter("#userName", user)).Select(items => new Feed
{
Id = (int)items[0],
Title = items[1].ToString(),
Body = items[2].ToString(),
Link = items[3].ToString(),
PubDate = (DateTime) items[4]
});
And items[4] is a datetime which can be null in database. So, how can check something like
if(items[4] is DateTime)
{
PubDate = (DateTime) items[4]
}
One more option would be to declare PubDate as nullable inside class Feeddeclaration.
Like this:
class Feed {
public DateTime? PubDate {get;set;}
...
}
This will expose truth from database into data access layer and shift your null checks one level up.
See: Nullable types in c#
May be you can use ternary operator here.
return _requestRepository.ExecuteProcReader(myRequest,new SqlParameter("#userName", user)).Select(items => new Feed
{
Id = (int)items[0],
Title = items[1].ToString(),
Body = items[2].ToString(),
Link = items[3].ToString(),
PubDate = ((DateTime)items[4]).HasValue ? (DateTime) items[4] : DateTime.Now
//Or any date you want to use
});
You should also check for DBNull.Value when getting data from a database.
Here's what I'll do :
PubDate = (item[4] == null || item[4] == DBNull.Value ? DateTime.Now : (DateTime)item[4])
If you have multiple fields that can be NULL in database, you can put it in an extension method as :
public static object GetDBValue(this object value, object defaultValue)
{
return value == null || value == DBNull.Value ? defaultValue : value;
}
And call it with :
PubDate = (DateTime)date1.GetDBValue(DateTime.Now);
I'm trying to update my table with this LINQ query
public void updateProduct(
int selectedIDToUpdate,
string prodNAMEToUp,
double prodPriceToUp,
string prodTYPEToUp,
int prodMANUToUp,
int prodCODEToUp)
{
DataClassesLINQEPOSDataContext dcld = new DataClassesLINQEPOSDataContext();
TBLPRODUCT tblprod = (from prod in dcld.TBLPRODUCTs
where prod.product_id == selectedIDToUpdate
select prod).First();
tblprod.product_name = prodNAMEToUp;
tblprod.product_price = prodPriceToUp;
tblprod.product_type = prodTYPEToUp;
tblprod.product_manufacturer = prodMANUToUp;
tblprod.product_code = prodCODEToUp;
dcld.SubmitChanges();
}
and then when I start to run the program I have this error
"InvalidCastException was unhandled"
"Specified cast is not valid."
Sorry I cant post image because I dont have enough reputation "points" :(
this is the control to pass the parameter on my class.
private void btnSaveToUpdate_Click(object sender, EventArgs e)
{
if (txtNameToUpdate.Text != "" ||
txtPriceToUpdate.Text != "" ||
txtTypeToUpdate.Text != "" ||
txtCodeToUpdate.Text != "")
{
Connection_Products update = new Connection_Products();
int selctedID = selectedIDToUpdate;
string prodNAMEToUp = txtNameToUpdate.Text;
double prodPriceToUp = double.Parse(txtPriceToUpdate.Text);
string prodTYPEToUp = txtTypeToUpdate.Text;
int prodMANUToUp = Convert.ToInt32(cmbManufacturerToUpdate.SelectedValue);
int prodCODEToUp = Convert.ToInt32(txtCodeToUpdate.Text);
update.updateProduct(selctedID, prodNAMEToUp, prodPriceToUp,
prodTYPEToUp, prodMANUToUp, prodCODEToUp);
}
else
{
MessageBox.Show("Error");
}
}
You most likely have some datatype mismatch between the values that you are trying to store and the data types of the columns in the database. This would be in one of the numeric columns.
If the prodPriceToUp column uses the money data type, this maps to a decimal type in Linq2Sql. You are trying to cast the double for the input parameter to decimal, which may be causing this issue. Try converting prodPriceToUp to a decimal before saving it.
I guess you are missing something in type mapping between updateProduct params and properties in tblprod. Please check here you are using correct types
This is because one of the following is trying to cast into an invalid type:
tblprod.product_name = prodNAMEToUp;
tblprod.product_price = prodPriceToUp;
tblprod.product_type = prodTYPEToUp;
tblprod.product_manufacturer = prodMANUToUp;
tblprod.product_code = prodCODEToUp;
Check for each of the these that the type of the left side is the same as the type of the right side. for example ensure that "tblprod.product_name" is a string property as you are trying to save a string to that property.
It is also possible that in your LINQ query, the where clause may have this problem, ensure that "prod.product_id" is an integer and not something else like a long or a short.
if these are all ok and you are still getting the exception then you will need to tell use what line is throwing the exception, and give use the details of the structure of tblprod;
Howsit!
I encounter an error when i get a null value in my datareader.
public List<Complaint> View_all_complaints()
{
csDAL objdal= new csDAL();
List<Complaint> oblcomplist=new List<Complaint>();
using( IDataReader dr=objdal.executespreturndr("View_all_complaints"))
{
while (dr.Read())
{
Complaint objcomp= new Complaint();
populate_reader(dr,objcomp);
oblcomplist.Add(objcomp);
}
}
return oblcomplist;
}
public void populate_reader(IDataReader dr, Complaint objcomp)
{
objcomp.ref_num = dr.GetString(0);
objcomp.type = dr.GetString(1);
objcomp.desc = dr.GetString(2);
objcomp.date = dr.GetDateTime(3);
objcomp.housenum = dr.GetInt32(4);
objcomp.streetnum = dr.GetInt32(5);
objcomp.status = dr.GetString(6);
objcomp.priority = dr.GetString(7);
objcomp.cid = dr.GetInt32(8);
if (!dr.IsDBNull(9))
{
objcomp.resolved_date = dr.GetDateTime(9);
}
}
in sql resolved date allows null values, this is so because only when a complaint has been resolved , it must reflect that date otherwise it should be null.
if dr.getdatetime(9) is null then it must just set a string saying "Not Resolved"
please help!
You haven't shown what your Complaint type looks like, but basically you'll want to make sure that its resolved_date is of type DateTime? aka Nullable<DateTime>. That allows you to model a missing value elegantly.
As for displaying it - you haven't shown anything about where you display the data, but you'd want something like:
string text = complaint.ResolvedDate.HasValue ? complaint.ResolvedDate.ToString()
: "Not Resolved";
(I've changed this to use a property with the idiomatic name at the same time...)
IDataReader has a "IsDBNull" method, that should be called before calling GetXXX(), in case your value is not nullable.
For example:
objcomp.date = dr.GetDateTime(3);
should be:
objcomp.date = dr.IsDBNull(3) ? DateTime.MinValue : dr.GetDateTime(3);