ASP.NET Table Adapter date overflow while update - c#

I am creating an front end to the AdventureWorks sample database.
I am trying to update a row in HumanResources.Department.
I am using a DataSet with Table Adapter for this table.
Inserting and updating a row causes issues :
public Department InserDepartment(Department department)
{
try
{
department.ModifiedDate = DateTime.Now;
Int32 id = departmentTableAdapter.Insert(department.Name, department.GroupName, department.ModifiedDate);
return new Department();
}
catch (Exception ex)
{
return new Department();
}
}
public Department UpdateDepratment(Department department)
{
try
{
HumanResourcesDataSet.DepartmentDataTable tblDepartments = departmentTableAdapter.GetDataByDepartmentId(department.DepartmentID);
HumanResourcesDataSet.DepartmentRow departmentRow = tblDepartments[0];
departmentRow.Name = department.Name;
department.GroupName = department.GroupName;
department.ModifiedDate = DateTime.Now;
departmentTableAdapter.Update(tblDepartments);
department = GetDepartment(department.DepartmentID);
return department;
}
catch (Exception ex)
{
// TBD
}
}
Following exception occures:
The fractional part of the provided time value overflows the scale of the corresponding SQL Server parameter or column. Increase bScale in DBPARAMBINDINFO or column scale to correct this error.
The issue is caused by following line in my update method:
department.ModifiedDate = DateTime.Now;
The data set accepts a DateTime class for this column, the database definition is a datetime, not null.
I have implemented datetime columns in other databases, and never had this issue.
What am I missing, that causes the issue?
Where should I search for solution to this issue?

So, i did not entirely found a cause and a proper solution for this issue. I added new stored procedure for an update on the table in question, which seems to solve some issues. The issue is somewhere in my data provider (System.Data.OleDb) and my SQL server.
The server is a SQL - Express. I imported the database from a .bak file.
In the stored procedure, i set ModifiedDate = CURRENT_TIMESTAMP, and pass the other values as param.
My assumption is, that my update interfered with folloving SQL script
[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_Department_ModifiedDate] DEFAULT (GETDATE())
I don't really want to tinker wiht the structure of the database and change a default, since i don't understand the database that well so far.
I can't really ignore the column as well, since I can update only an entire row with my table adapter, which includes the date that is set in my DataRow instance.

Related

String or binary data would be truncated exception when inserting data [duplicate]

I am running data.bat file with the following lines:
Rem Tis batch file will populate tables
cd\program files\Microsoft SQL Server\MSSQL
osql -U sa -P Password -d MyBusiness -i c:\data.sql
The contents of the data.sql file is:
insert Customers
(CustomerID, CompanyName, Phone)
Values('101','Southwinds','19126602729')
There are 8 more similar lines for adding records.
When I run this with start > run > cmd > c:\data.bat, I get this error message:
1>2>3>4>5>....<1 row affected>
Msg 8152, Level 16, State 4, Server SP1001, Line 1
string or binary data would be truncated.
<1 row affected>
<1 row affected>
<1 row affected>
<1 row affected>
<1 row affected>
<1 row affected>
Also, I am a newbie obviously, but what do Level #, and state # mean, and how do I look up error messages such as the one above: 8152?
From #gmmastros's answer
Whenever you see the message....
string or binary data would be truncated
Think to yourself... The field is NOT big enough to hold my data.
Check the table structure for the customers table. I think you'll find that the length of one or more fields is NOT big enough to hold the data you are trying to insert. For example, if the Phone field is a varchar(8) field, and you try to put 11 characters in to it, you will get this error.
I had this issue although data length was shorter than the field length.
It turned out that the problem was having another log table (for audit trail), filled by a trigger on the main table, where the column size also had to be changed.
In one of the INSERT statements you are attempting to insert a too long string into a string (varchar or nvarchar) column.
If it's not obvious which INSERT is the offender by a mere look at the script, you could count the <1 row affected> lines that occur before the error message. The obtained number plus one gives you the statement number. In your case it seems to be the second INSERT that produces the error.
Just want to contribute with additional information: I had the same issue and it was because of the field wasn't big enough for the incoming data and this thread helped me to solve it (the top answer clarifies it all).
BUT it is very important to know what are the possible reasons that may cause it.
In my case i was creating the table with a field like this:
Select '' as Period, * From Transactions Into #NewTable
Therefore the field "Period" had a length of Zero and causing the Insert operations to fail. I changed it to "XXXXXX" that is the length of the incoming data and it now worked properly (because field now had a lentgh of 6).
I hope this help anyone with same issue :)
Some of your data cannot fit into your database column (small). It is not easy to find what is wrong. If you use C# and Linq2Sql, you can list the field which would be truncated:
First create helper class:
public class SqlTruncationExceptionWithDetails : ArgumentOutOfRangeException
{
public SqlTruncationExceptionWithDetails(System.Data.SqlClient.SqlException inner, DataContext context)
: base(inner.Message + " " + GetSqlTruncationExceptionWithDetailsString(context))
{
}
/// <summary>
/// PArt of code from following link
/// http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
static string GetSqlTruncationExceptionWithDetailsString(DataContext context)
{
StringBuilder sb = new StringBuilder();
foreach (object update in context.GetChangeSet().Updates)
{
FindLongStrings(update, sb);
}
foreach (object insert in context.GetChangeSet().Inserts)
{
FindLongStrings(insert, sb);
}
return sb.ToString();
}
public static void FindLongStrings(object testObject, StringBuilder sb)
{
foreach (var propInfo in testObject.GetType().GetProperties())
{
foreach (System.Data.Linq.Mapping.ColumnAttribute attribute in propInfo.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true))
{
if (attribute.DbType.ToLower().Contains("varchar"))
{
string dbType = attribute.DbType.ToLower();
int numberStartIndex = dbType.IndexOf("varchar(") + 8;
int numberEndIndex = dbType.IndexOf(")", numberStartIndex);
string lengthString = dbType.Substring(numberStartIndex, (numberEndIndex - numberStartIndex));
int maxLength = 0;
int.TryParse(lengthString, out maxLength);
string currentValue = (string)propInfo.GetValue(testObject, null);
if (!string.IsNullOrEmpty(currentValue) && maxLength != 0 && currentValue.Length > maxLength)
{
//string is too long
sb.AppendLine(testObject.GetType().Name + "." + propInfo.Name + " " + currentValue + " Max: " + maxLength);
}
}
}
}
}
}
Then prepare the wrapper for SubmitChanges:
public static class DataContextExtensions
{
public static void SubmitChangesWithDetailException(this DataContext dataContext)
{
//http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
try
{
//this can failed on data truncation
dataContext.SubmitChanges();
}
catch (SqlException sqlException) //when (sqlException.Message == "String or binary data would be truncated.")
{
if (sqlException.Message == "String or binary data would be truncated.") //only for EN windows - if you are running different window language, invoke the sqlException.getMessage on thread with EN culture
throw new SqlTruncationExceptionWithDetails(sqlException, dataContext);
else
throw;
}
}
}
Prepare global exception handler and log truncation details:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
string message = ex.Message;
//TODO - log to file
}
Finally use the code:
Datamodel.SubmitChangesWithDetailException();
Another situation in which you can get this error is the following:
I had the same error and the reason was that in an INSERT statement that received data from an UNION, the order of the columns was different from the original table. If you change the order in #table3 to a, b, c, you will fix the error.
select a, b, c into #table1
from #table0
insert into #table1
select a, b, c from #table2
union
select a, c, b from #table3
on sql server you can use SET ANSI_WARNINGS OFF like this:
using (SqlConnection conn = new SqlConnection("Data Source=XRAYGOAT\\SQLEXPRESS;Initial Catalog='Healthy Care';Integrated Security=True"))
{
conn.Open();
using (var trans = conn.BeginTransaction())
{
try
{
using cmd = new SqlCommand("", conn, trans))
{
cmd.CommandText = "SET ANSI_WARNINGS OFF";
cmd.ExecuteNonQuery();
cmd.CommandText = "YOUR INSERT HERE";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "SET ANSI_WARNINGS ON";
cmd.ExecuteNonQuery();
trans.Commit();
}
}
catch (Exception)
{
trans.Rollback();
}
}
conn.Close();
}
I had the same issue. The length of my column was too short.
What you can do is either increase the length or shorten the text you want to put in the database.
Also had this problem occurring on the web application surface.
Eventually found out that the same error message comes from the SQL update statement in the specific table.
Finally then figured out that the column definition in the relating history table(s) did not map the original table column length of nvarchar types in some specific cases.
I had the same problem, even after increasing the size of the problematic columns in the table.
tl;dr: The length of the matching columns in corresponding Table Types may also need to be increased.
In my case, the error was coming from the Data Export service in Microsoft Dynamics CRM, which allows CRM data to be synced to an SQL Server DB or Azure SQL DB.
After a lengthy investigation, I concluded that the Data Export service must be using Table-Valued Parameters:
You can use table-valued parameters to send multiple rows of data to a Transact-SQL statement or a routine, such as a stored procedure or function, without creating a temporary table or many parameters.
As you can see in the documentation above, Table Types are used to create the data ingestion procedure:
CREATE TYPE LocationTableType AS TABLE (...);
CREATE PROCEDURE dbo.usp_InsertProductionLocation
#TVP LocationTableType READONLY
Unfortunately, there is no way to alter a Table Type, so it has to be dropped & recreated entirely. Since my table has over 300 fields (😱), I created a query to facilitate the creation of the corresponding Table Type based on the table's columns definition (just replace [table_name] with your table's name):
SELECT 'CREATE TYPE [table_name]Type AS TABLE (' + STRING_AGG(CAST(field AS VARCHAR(max)), ',' + CHAR(10)) + ');' AS create_type
FROM (
SELECT TOP 5000 COLUMN_NAME + ' ' + DATA_TYPE
+ IIF(CHARACTER_MAXIMUM_LENGTH IS NULL, '', CONCAT('(', IIF(CHARACTER_MAXIMUM_LENGTH = -1, 'max', CONCAT(CHARACTER_MAXIMUM_LENGTH,'')), ')'))
+ IIF(DATA_TYPE = 'decimal', CONCAT('(', NUMERIC_PRECISION, ',', NUMERIC_SCALE, ')'), '')
AS field
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '[table_name]'
ORDER BY ORDINAL_POSITION) AS T;
After updating the Table Type, the Data Export service started functioning properly once again! :)
When I tried to execute my stored procedure I had the same problem because the size of the column that I need to add some data is shorter than the data I want to add.
You can increase the size of the column data type or reduce the length of your data.
A 2016/2017 update will show you the bad value and column.
A new trace flag will swap the old error for a new 2628 error and will print out the column and offending value. Traceflag 460 is available in the latest cumulative update for 2016 and 2017:
https://support.microsoft.com/en-sg/help/4468101/optional-replacement-for-string-or-binary-data-would-be-truncated
Just make sure that after you've installed the CU that you enable the trace flag, either globally/permanently on the server:
...or with DBCC TRACEON:
https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-traceon-trace-flags-transact-sql?view=sql-server-ver15
Another situation, in which this error may occur is in
SQL Server Management Studio. If you have "text" or "ntext" fields in your table,
no matter what kind of field you are updating (for example bit or integer).
Seems that the Studio does not load entire "ntext" fields and also updates ALL fields instead of the modified one.
To solve the problem, exclude "text" or "ntext" fields from the query in Management Studio
This Error Comes only When any of your field length is greater than the field length specified in sql server database table structure.
To overcome this issue you have to reduce the length of the field Value .
Or to increase the length of database table field .
If someone is encountering this error in a C# application, I have created a simple way of finding offending fields by:
Getting the column width of all the columns of a table where we're trying to make this insert/ update. (I'm getting this info directly from the database.)
Comparing the column widths to the width of the values we're trying to insert/ update.
Assumptions/ Limitations:
The column names of the table in the database match with the C# entity fields. For eg: If you have a column like this in database:
You need to have your Entity with the same column name:
public class SomeTable
{
// Other fields
public string SourceData { get; set; }
}
You're inserting/ updating 1 entity at a time. It'll be clearer in the demo code below. (If you're doing bulk inserts/ updates, you might want to either modify it or use some other solution.)
Step 1:
Get the column width of all the columns directly from the database:
// For this, I took help from Microsoft docs website:
// https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.getschema?view=netframework-4.7.2#System_Data_SqlClient_SqlConnection_GetSchema_System_String_System_String___
private static Dictionary<string, int> GetColumnSizesOfTableFromDatabase(string tableName, string connectionString)
{
var columnSizes = new Dictionary<string, int>();
using (var connection = new SqlConnection(connectionString))
{
// Connect to the database then retrieve the schema information.
connection.Open();
// You can specify the Catalog, Schema, Table Name, Column Name to get the specified column(s).
// You can use four restrictions for Column, so you should create a 4 members array.
String[] columnRestrictions = new String[4];
// For the array, 0-member represents Catalog; 1-member represents Schema;
// 2-member represents Table Name; 3-member represents Column Name.
// Now we specify the Table_Name and Column_Name of the columns what we want to get schema information.
columnRestrictions[2] = tableName;
DataTable allColumnsSchemaTable = connection.GetSchema("Columns", columnRestrictions);
foreach (DataRow row in allColumnsSchemaTable.Rows)
{
var columnName = row.Field<string>("COLUMN_NAME");
//var dataType = row.Field<string>("DATA_TYPE");
var characterMaxLength = row.Field<int?>("CHARACTER_MAXIMUM_LENGTH");
// I'm only capturing columns whose Datatype is "varchar" or "char", i.e. their CHARACTER_MAXIMUM_LENGTH won't be null.
if(characterMaxLength != null)
{
columnSizes.Add(columnName, characterMaxLength.Value);
}
}
connection.Close();
}
return columnSizes;
}
Step 2:
Compare the column widths with the width of the values we're trying to insert/ update:
public static Dictionary<string, string> FindLongBinaryOrStringFields<T>(T entity, string connectionString)
{
var tableName = typeof(T).Name;
Dictionary<string, string> longFields = new Dictionary<string, string>();
var objectProperties = GetProperties(entity);
//var fieldNames = objectProperties.Select(p => p.Name).ToList();
var actualDatabaseColumnSizes = GetColumnSizesOfTableFromDatabase(tableName, connectionString);
foreach (var dbColumn in actualDatabaseColumnSizes)
{
var maxLengthOfThisColumn = dbColumn.Value;
var currentValueOfThisField = objectProperties.Where(f => f.Name == dbColumn.Key).First()?.GetValue(entity, null)?.ToString();
if (!string.IsNullOrEmpty(currentValueOfThisField) && currentValueOfThisField.Length > maxLengthOfThisColumn)
{
longFields.Add(dbColumn.Key, $"'{dbColumn.Key}' column cannot take the value of '{currentValueOfThisField}' because the max length it can take is {maxLengthOfThisColumn}.");
}
}
return longFields;
}
public static List<PropertyInfo> GetProperties<T>(T entity)
{
//The DeclaredOnly flag makes sure you only get properties of the object, not from the classes it derives from.
var properties = entity.GetType()
.GetProperties(System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.DeclaredOnly)
.ToList();
return properties;
}
Demo:
Let's say we're trying to insert someTableEntity of SomeTable class that is modeled in our app like so:
public class SomeTable
{
[Key]
public long TicketID { get; set; }
public string SourceData { get; set; }
}
And it's inside our SomeDbContext like so:
public class SomeDbContext : DbContext
{
public DbSet<SomeTable> SomeTables { get; set; }
}
This table in Db has SourceData field as varchar(16) like so:
Now we'll try to insert value that is longer than 16 characters into this field and capture this information:
public void SaveSomeTableEntity()
{
var connectionString = "server=SERVER_NAME;database=DB_NAME;User ID=SOME_ID;Password=SOME_PASSWORD;Connection Timeout=200";
using (var context = new SomeDbContext(connectionString))
{
var someTableEntity = new SomeTable()
{
SourceData = "Blah-Blah-Blah-Blah-Blah-Blah"
};
context.SomeTables.Add(someTableEntity);
try
{
context.SaveChanges();
}
catch (Exception ex)
{
if (ex.GetBaseException().Message == "String or binary data would be truncated.\r\nThe statement has been terminated.")
{
var badFieldsReport = "";
List<string> badFields = new List<string>();
// YOU GOT YOUR FIELDS RIGHT HERE:
var longFields = FindLongBinaryOrStringFields(someTableEntity, connectionString);
foreach (var longField in longFields)
{
badFields.Add(longField.Key);
badFieldsReport += longField.Value + "\n";
}
}
else
throw;
}
}
}
The badFieldsReport will have this value:
'SourceData' column cannot take the value of
'Blah-Blah-Blah-Blah-Blah-Blah' because the max length it can take is
16.
Kevin Pope's comment under the accepted answer was what I needed.
The problem, in my case, was that I had triggers defined on my table that would insert update/insert transactions into an audit table, but the audit table had a data type mismatch where a column with VARCHAR(MAX) in the original table was stored as VARCHAR(1) in the audit table, so my triggers were failing when I would insert anything greater than VARCHAR(1) in the original table column and I would get this error message.
I used a different tactic, fields that are allocated 8K in some places. Here only about 50/100 are used.
declare #NVPN_list as table
nvpn varchar(50)
,nvpn_revision varchar(5)
,nvpn_iteration INT
,mpn_lifecycle varchar(30)
,mfr varchar(100)
,mpn varchar(50)
,mpn_revision varchar(5)
,mpn_iteration INT
-- ...
) INSERT INTO #NVPN_LIST
SELECT left(nvpn ,50) as nvpn
,left(nvpn_revision ,10) as nvpn_revision
,nvpn_iteration
,left(mpn_lifecycle ,30)
,left(mfr ,100)
,left(mpn ,50)
,left(mpn_revision ,5)
,mpn_iteration
,left(mfr_order_num ,50)
FROM [DASHBOARD].[dbo].[mpnAttributes] (NOLOCK) mpna
I wanted speed, since I have 1M total records, and load 28K of them.
This error may be due to less field size than your entered data.
For e.g. if you have data type nvarchar(7) and if your value is 'aaaaddddf' then error is shown as:
string or binary data would be truncated
You simply can't beat SQL Server on this.
You can insert into a new table like this:
select foo, bar
into tmp_new_table_to_dispose_later
from my_table
and compare the table definition with the real table you want to insert the data into.
Sometime it's helpful sometimes it's not.
If you try inserting in the final/real table from that temporary table it may just work (due to data conversion working differently than SSMS for example).
Another alternative is to insert the data in chunks, instead of inserting everything immediately you insert with top 1000 and you repeat the process, till you find a chunk with an error. At least you have better visibility on what's not fitting into the table.

SQL Exception Error C# ASP.Net

It's been awhile since I've messed with anything SQL, and I'm trying to build a little Todo app to learn some ASP.Net with C#. I'm using Visual Studio 2013 with whatever version of SQL Express it comes packaged with, all locally.
I have the following table todo_list, made with the following script, through Visual Studio:
CREATE TABLE [dbo].[todo_list] (
[id] INT NOT NULL,
[task] TEXT NOT NULL,
[complete] BIT NOT NULL,
[date] DATE NOT NULL,
PRIMARY KEY CLUSTERED ([id] ASC)
);
When the web application starts, I'm trying to get all of the records where complete is false. I'm assuming I can read/write to the complete column as true/false because of it being of type bit.
I get an exception thrown when the following code goes to execute...
private void Get_Tasks()
{
//Get the connection string
SqlConnection connection = new SqlConnection();
connection.ConnectionString = System.Configuration.ConfigurationManager.
ConnectionStrings["Database1ConnectionString"].ConnectionString;
//Build SQL query
string query = "SELECT * FROM todo_list WHERE complete=False";
System.Diagnostics.Debug.WriteLine(query);
//Build SQL Command Object
SqlCommand command = new SqlCommand(query, connection);
//Grab all uncompleted tasks from database
SqlDataReader cursor;
try
{
using(connection)
{
//Open and execute SQL stuffz...
connection.Open();
cursor = command.ExecuteReader();
//Get all the tasks
while (cursor.Read())
{
//Build the task from record set
Todo task = new Todo(
(int)cursor["id"], (string)cursor["task"],
(bool)cursor["complete"], (DateTime)cursor["date"]);
//Append to DOM
Page.ClientScript.RegisterStartupScript(this.GetType(), "alert" + UniqueID, "alert('About to append to DOM!');", true);
tasklist.InnerHtml = task.toHtml();
}
//Close connection
connection.Close();
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
connection.Close();
}
//TODO - Grab all completed tasks from database
}
The Exception that is thrown when cursor = command.ExecuteReader(); executes -
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll'
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'False'.
I have no idea why it is taking False as a column name?
Thanks in advance for any help!
You can change the False for 0 or for 'False'
Example
Your SQL query is invalid. Did you read the error message?
Have you tried running in in SQL Server Management Studio (assuming your using SQL Server...if not, the interactive tools of choice)?
Your query
select *
from todo_list
where complete = False
is [trying to, anyway] selecting all the rows from the table todo_list where the table's two columns complete and False are equal. Since your table has no column named False, SQL Server's query compiler gives you the obvious error::
Invalid column name 'False'
SQL Server's bit datatype is not a boolean in the C# sense. It's fundamentally a 1-bit integer whose domain is {0,1}. You need to rephrase your query like this:
select *
from todo_list
where complete = 0
The CLR bidirectionally maps SQL Server's bit to a CLR System.Boolean. If the bit column is nullable, any SQL Server null values will be mapped to the sole instance of System.DbNull.

"Data type mismatch" when using date Parameters

I am trying to implement CoolStorage in my project, but am running into an issue when using date parameters. When I pass in null as the date parameter it adds the record successfully, but if I pass an actual date through I get an error when calling .Save() to write the new record to the database. I have got the (Activa) CoolStorage source code and have found the point where it fails, but can't figure how to fix it.
The code where it fails is as follows (specifically the dbCommand.ExecuteNonQuery() line):
internal int ExecuteNonQuery(string sqlQuery, CSParameterCollection parameters)
{
long logId = Log(sqlQuery, parameters);
IDbCommand dbCommand = CreateCommand(sqlQuery, parameters);
try
{
dbCommand.ExecuteNonQuery();
return 1;
}
catch (InvalidOperationException)
{
return -1;
}
finally
{
LogEnd(logId);
}
}
The sqlQuery contains:
insert into [Schedule] ([TaskID],[StartTime],[MondayYn],[TuesdayYn],[WednesdayYn],[ThursdayYn],[FridayYn],[SaturdayYn],[SundayYn],[DefaultSysuserID],[DefaultTeamID],[ActiveYn])
values (#P17,#P18,#P19,#P20,#P21,#P22,#P23,#P24,#P25,#P26,#P27,#P28)
#P18 contains the offending date, which is a CSParameter object with a value of:
{17/12/2012 18:52:44}
Also, the database being used is Access. The error that's thrown is a OldDbException which reads {"Data type mismatch in criteria expression."}.
Can anyone offer any advice on how to resolve this?
EDIT: The Schedule StartTime field is defined in the Schedule table as Date/Time. I need it to have its required propetry set to True, but have disabled in order to test adding records by leaving StartTime out. The parameters are being applied via the CoolStorage classes as follows:
Schedule schedule = Schedule.New();
schedule.TaskID = task.TaskID;
schedule.StartTime = DateTime.Now;
schedule.MondayYn = true;
schedule.TuesdayYn = true;
schedule.WednesdayYn = true;
schedule.ThursdayYn = true;
schedule.FridayYn = true;
schedule.SaturdayYn = false;
schedule.SundayYn = false;
schedule.DefaultSysuserID = sysuser.SysuserID;
schedule.DefaultTeamID = sysuser.SysuserTeams.First().TeamID;
schedule.ActiveYn = true;
schedule.Save();
When I comment out the Schedule.StartTime = DateTime.Now line I can successfully add records, otherwise I get the error described above. I cannot change the format to text without editing my ORM mapping class, which will no doubt cause errors elsewhere. I guess I could alter the CoolStorage DataProvider class, but I'm assuming that this shouldn't be necessary?
EDIT2: As a test I intercepted the SQL posted above to remove the #P18 reference and hard code the date in its place and the record added correctly:
insert into [Schedule] ([TaskID],[StartTime],[MondayYn],[TuesdayYn],[WednesdayYn],[ThursdayYn],[FridayYn],[SaturdayYn],[SundayYn],[DefaultSysuserID],[DefaultTeamID],[ActiveYn])
values (#P17,#2012-12-01 12:00:00#,#P19,#P20,#P21,#P22,#P23,#P24,#P25,#P26,#P27,#P28)
I also tried modifying the value of the parameter by casting it as a string formatted as #yyyy-MM-dd hh:mm:ss# however I still received the Data type mismatch in criteria expression error.
EDIT3: I have fixed it by following Abhishek's (edit - also Dean's) suggestion of converting the DateTime to a string by amending the CSParameterCollection class as follows. Hopefully this won't cause problems if I decide to use a different database but it's fixed it for Access:
public CSParameter this[string name]
{
get
{
CSParameter parameter;
_parameterMap.TryGetValue(name, out parameter);
if (parameter.Value.GetType().Equals(typeof(DateTime)))
{
DateTime date = (DateTime)parameter.Value;
string dateString = date.ToString("yyyy-MM-dd hh:mm:ss");
parameter.Value = dateString;
}
return parameter;
}
}
I strongly feel that the problem is because the parameters are not in the same order when you are adding them to the parameter collection.
Make sure that they are in the same order and this applies to both sql statements or stored procedures.
ADO.NET does not support named parameters when using an OLEDB provider, and since you are connecting to an Access DB, you are actually using an OLEDB provider. So the order of the parameters does matter.
If they are in order and it's still not working, then I think that it might be an issue with the DateTime. Try converting it to string before adding it as a parameter.

Catching specific exception while inserting data in acces database

I am inserting data into access databse and if the data is already present i.e. duplicate enty found then just need to update that enty.
public bool InsertInToTooltip()
{
InitializeSettingsDatabase();
OleDbCommand command;
command = new OleDbCommand(//Query, settingsDbConn);
try
{
command.ExecuteNonQuery();
}
catch (Exception e)
{
UpdateTable();
}
CloseDatabase();
return true;
}
Is there any specific exception thrown in case of inserting duplicate entries in acces database?
You should check if the record exists and the issue an insert or update rather than using an exception for this. You could wrap that logic in a stored procedure or do a select the an additional query.
All in one
IF EXIST (select true from table where id = #id)
Update table set x = y
Else
Insert into table (x, y) values ('x', 'y')
Try using a DataAdapter if you are using controls such as DataGridViews, ComboBoxes etc... This will automatically do all the handling for you as long as you link it to a database source and control. Otherwise i would rather do an extra sql statement that will check if the data is available in the database e.g.
SELECT * FROM TABLE WHERE COLUMN = _VAR
Based on what it returns you can either INSERT or Update. I hope this helps.

How to create "embedded" SQL 2008 database file if it doesn't exist?

I've created a database application using C#, ADO.Net and an embedded MS SQL 2008 database file (that attaches to MS SQL 2008 Express) which I created in Server Management Studio. Can someone point me to a resource that describes how I can programmatically create the database file if it is missing (like right after my application is installed)?
If it were me (when it is me...):
You don't particularly want to be trying to make database files work by copying them and attaching them - there are reasons why you might want to but I believe these to be exceptions rather than rules.
Accordingly what you need to do is to script creation of the database i.e. to use SQL DDL to create the database and the tables and all the other stuff in your schema.
Pretty much all you need to enable you to do this is appropriate rights to the server instance and then a connection string (which you can probably build apart from the server/instance name).
From here:
Is there a database? If not create it.
If there is a database, is it the right schema version? If too low either update it or advise the user and back out gracefully depending on how you want things too work. If too high just back out and advise that an updated version of the application is required
All is as it should be, carry on.
From a code point of view: method to determine if a database exists; method to create an standard "empty" database with a version table and a version number of 0; methods to bring the schema up to the current version by running the appropriate DDL (we encode ours into C# because it provides more flexibility but you could equally run DDL scripts in sequence).
Does it exist:
public virtual bool Exists()
{
bool exists = false;
string masterConnectionString = this.CreateConnectionString(this.Server, this.FailoverServer, "master");
this.DBConnection.ConnectionString = masterConnectionString;
this.DBConnection.Open();
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = this.DBConnection;
cmd.CommandText = "SELECT COUNT(name) FROM sysdatabases WHERE name = #DBName";
cmd.Parameters.AddWithValue("#DBName", this.DBName);
exists = (Convert.ToInt32(cmd.ExecuteScalar()) == 1);
}
finally
{
this.DBConnection.Close();
}
return exists;
}
Create a new database:
public virtual void CreateNew()
{
string createDDL = #"CREATE DATABASE [" + this.DBName + "]";
this.BuildMasterConnectionString();
this.DBConnection.Open();
try
{
this.ExecuteSQLStmt(createDDL, this.DefaultSQLTimeout, null);
}
finally
{
this.DBConnection.Close();
}
createDDL = #"
CREATE TABLE AAASchemaVersion
(
Version int NOT NULL,
DateCreated datetime NOT NULL,
Author nvarchar(30) NOT NULL,
Notes nvarchar(MAX) NULL
);
ALTER TABLE AAASchemaVersion ADD CONSTRAINT PK_Version PRIMARY KEY CLUSTERED
(
Version
);
INSERT INTO AAASchemaVersion
(Version, DateCreated, Author, Notes)
VALUES
(0, GETDATE(), 'James Murphy', 'Empty Database')
";
this.BuildConnectionString();
this.ConnectionString += ";pooling=false";
this.DBConnection.Open();
try
{
this.ExecuteSQLStmt(createDDL, this.DefaultSQLTimeout, null);
}
catch (Exception ex)
{
throw new Exception("Exception while creating / initialising AAASchemaVersion", ex);
}
finally
{
this.DBConnection.Close();
}
}
The update code is a tad more complex but basically runs stuff like this:
CREATE TABLE AuditUser
(
ID int IDENTITY(1,1) NOT NULL,
UserSourceTypeID tinyint NOT NULL,
DateCreated smalldatetime NOT NULL,
UserName nvarchar(100) NOT NULL
);
ALTER TABLE AuditUser
ADD CONSTRAINT
PK_AuditUser PRIMARY KEY CLUSTERED
(
ID
),
CONSTRAINT [FK_AuditUser_UserSourceType] FOREIGN KEY
(
UserSourceTypeID
) REFERENCES UserSourceType (
ID
);
All wrapped up in a transaction per update - so that if the update fails you should leave the database is a known good state.
Why do it this way (in code, which is not without its trials?) well the end result is a high degree of confidence that the schema your app is talking to is the schema your app expects to talk to... right tables, right columns (in the right order, that are the right type and the right length), etc, etc. and that this will continue to be the case over time.
Apologies if this is a bit long - but this is something I'm quite keen on...
If the "embedded MS SQL" is a "Microsoft SQL Server Compact 3.5":
using (SqlCeEngine sqlCeEngine = new SqlCeEngine(connectionString))
sqlCeEngine.CreateDatabase();

Categories