Inserting data with Dapper with DateTime2 throws SqlDateTime overflow exception - c#

If I have an object such as:
public class Person
{
public int Id {get;set;}
public string Name {get;set;}
public DateTime DOB {get;set;}
}
If I set the name on my object and DOB is DateTime.MinValue and use Dapper like so:
INSERT INTO [Person] ([Person].[Name], [Person].[DOB]) VALUES (#Name, #DOB);
SELECT CAST(SCOPE_IDENTITY() AS BIGINT) AS [Id]
connection.Query<long>(sql, entity);
This throws SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
However if I execute the SQL in SQL Management Studio with a string version '0001-01-01 00:00:00' it inserts into the db fine.
Any ideas how to get this to work?
Thanks
UPDATE:
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[DOB] [datetime2](7) NULL,
[Name] [nvarchar](20) NOT NULL,
CONSTRAINT [PK_Referrer_Referee] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

.Net DateTime should handle both.
Dapper is mapping datetime to DbType DateTime and not DbType.DateTime2 which is what you need.
https://github.com/SamSaffron/dapper-dot-net/blob/master/Dapper%20NET40/SqlMapper.cs#L384
typeMap[typeof(DateTime)] = DbType.DateTime;
typeMap[typeof(DateTime?)] = DbType.DateTime;
But you can add a TypeMap yourself but then you need to create a datetime2 type/class.

Try looking at this SO answer, about mapping the DateTime2 type in Dapper

Issue is within insert statement. You have specified three values and two column names. Query like this will work or add column name corresponding to variable #RefereeId.
INSERT INTO [Person] ([Person].[Name], [Person].[DOB]) VALUES (#Name, #DOB);

Related

How do I use Dapper to insert a list<myobject> as parameter to a stored procedure

I have a SQL Server table with 10 columns:
CREATE TABLE [bank].[CommonPostingsFromBankFiles]
(
[Id] [INT] IDENTITY(1,1) NOT NULL,
[BankRegistrationNumber] [INT] NOT NULL,
[BankAccountNumber] [BIGINT] NOT NULL,
[BankName] [NVARCHAR](50) NULL,
[BankAccount] [NVARCHAR](50) NULL,
[PostingAmount] [DECIMAL](18, 2) NOT NULL,
[PostingDate] [DATE] NOT NULL,
[Primo] [CHAR](1) NULL,
[PostingText] [NVARCHAR](100) NULL,
[HideThisRecord] [BIT] NULL,
CONSTRAINT [PK_CommonPostingsFromBankFiles]
PRIMARY KEY CLUSTERED ([BankRegistrationNumber] ASC,
[BankAccountNumber] ASC,
[PostingAmount] ASC,
[PostingDate] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
)
and a stored procedure that takes 7 parameters:
ALTER PROCEDURE [bank].[spInsertCommonPostings]
(#BankRegistrationNumber INT,
#BankAccountNumber BIGINT,
#BankName NVARCHAR(50),
#PostingAmount DECIMAL(18, 2),
#PostingDate DATE,
#Primo CHAR(1),
#PostingText NVARCHAR(100))
AS
BEGIN
IF NOT EXISTS (SELECT *
FROM bank.CommonPostingsFromBankFiles
WHERE BankRegistrationNumber = #BankRegistrationNumber
AND BankAccountNumber = #BankAccountNumber
AND BankName = #BankName
AND PostingAmount = #PostingAmount
AND PostingDate = #PostingDate)
INSERT INTO bank.CommonPostingsFromBankFiles (BankRegistrationNumber, BankAccountNumber,
BankName, PostingAmount,
PostingDate, Primo, PostingText)
VALUES (#BankRegistrationNumber, #BankAccountNumber,
#BankName, #PostingAmount,
#PostingDate, #Primo, #PostingText);
END;
What I want is to use Dapper to write a List<Postings> to the table using the stored procedure.
I have searched and searched but found no example that helped me.
If I do a
connection.Execute(sql: "spMyStoredProc", MyList, commandType: CommandType.StoredProcedure);
I get an error
Procedure or function spMyStoredProc has too many arguments specified
If I replace the name of the stored procedure with the sql from the stored procedure and set CommandType to Text it works as expected.
Could anybody please post me an example showing how to insert my list using my stored procedure.
Thanks,
Steffen
Simplistically, and assuming the names of the properties in your c# object are identical to the names of the parameters in your stored proc, you could:
MyList.ForEach(x => connection.Execute(sql: "spMyStoredProc", x, commandType: CommandType.StoredProcedure));
If the param/props aren't aligned it may be simplest to provide an anonymous type populated with values from x that covers them
MyList.ForEach(x => connection.Execute(
sql: "spMyStoredProc",
new { BankRegistrationNumber = x.BankRN, ... },
commandType: CommandType.StoredProcedure
));
For a list of 10 objects it will invoke the proc 10 times; it's not the fastest way to do it, but I don't think you've stated any particular goals re performance etc.

writing enum value to db col

I'm using what I consider to be very standard C# and T-SQL code to populate a column of datatype char(1) based on a C# enum with char values :
I am seeing an asterisk * written to db when a C should be written -- but I have been unable to find a consistent repo and I have no idea how this could happen.
Some questions are how could a row be inserted into my db that includes a value not present in my enum ? Does the asterisk have any special meaning in this context ?
Here's representative code - stripped-down for readability :
CREATE TABLE [MY_TABLE](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[STATUS] [char](1) NOT NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
CREATE PROCEDURE [INSERT_TO_MY_TABLE]
(
#status [char](1)
)
AS
BEGIN
INSERT INTO [MY_TABLE]
(
[STATUS]
)
VALUES
(
#status
)
END
public enum Status
{
Adult = 'A',
Juvenile = 'J',
Child = 'C'
}
Statu status = Status.Child;
using (var command = connection.CreateCommand())
{
command.CommandText = $"INSERT_TO_MY_TABLE";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter($"#status", (char)status));
command.ExecuteNonQuery();
}
It looks like you have Status and StatusEnum active in your code - two different unrelated Enums
You want to change StatusEnum to Status
Also a string cast could generate the value "Child" instead of 'C' as an FYI.
status.ToString().Substring(0, 1) - would pull the first char of "Child" not the value of 'C'

How can I check if the DateTimes of an item is within the range of two other dates?

I am a new ASP.NET developer and I have 2 inputs in a form as DateTimes; StartDate and EndDate. I want to make sure that both of them are within the StartDate and EndDate of the Parent from another table. The logic should be as following:
Check if the StartDate of the items comes before the EndDate.
Check if the StartDate & EndDate of the inserted item is within the range of the StartDate and EndDate in the Customers table
So how can I do this logic?
For your information, I have two tables in the database, namely; Customers and Items.Their schema are:
Customers Table:
CREATE TABLE [dbo].[Customers](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[Job] [varchar](50) NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Items Table:
CREATE TABLE [dbo].[Items](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Description] [varchar](50) NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
[CustomerID] [int] NOT NULL,
CONSTRAINT [PK_Items] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Items] WITH CHECK ADD CONSTRAINT [FK_Items_Customers] FOREIGN KEY([CustomerID])
REFERENCES [dbo].[Customers] ([ID])
GO
ALTER TABLE [dbo].[Items] CHECK CONSTRAINT [FK_Items_Customers]
GO
My C# Code:
protected void btnSubmit_Click(object sender, EventArgs e)
{
DateTime startDate = Convert.ToDateTime(txtStartDate.Text);
DateTime endDate = Convert.ToDateTime(txtEndDate.Text);
if (DateTime.Compare(startDate, endDate) <= 0)
{
using (TestDBEntities1 TEntities = new TestDBEntities1())
{
var newItem = new Item
{
Name = txtName.Text,
Description = txtDesc.Text,
StartDate = startDate,
EndDate = endDate,
CustomerID = Convert.ToInt32(ComboBox1.SelectedValue)
};
TEntities.Items.AddObject(newItem);
TEntities.SaveChanges();
}
lblMessage.Text = "Successfully Added :)";
}
else
{
lblMessage.Text = "Error!!!";
}
}
NOTE: I am using LINQ for querying the database. I am only missing the part of doing the logic for checking if the StartDate & EndDate of the inserted item is within the Dates in the Customers table.
Explanation:
For example, let us assume we have StartDate#1 and EndDate#1 for an item that will be inserted. In the Customers table, I have StartDate#2 and EndDate#2. The logic should do the following:
check if the StartDate#1 comes before EndDate#1
Then, check if StartDate#1 and EndDate#1 are falling within the range of StartDate#2 and EndDate#2

Saving server date and time

I want to save the time and date within my news but in the method below I save the time of the user and if his/her time is wrong, the wrong time will be save. How can I use the server's time instead.
SqlConnection sqlconn = new SqlConnection(connStr);
SqlCommand sqlcmd = new SqlCommand("insert into SubmitManuscript(username,title,authors,type,date,upload,reviewer1,email1,reviewer2,email2,reviewer3,email3)values(#username,#title,#authors,#type,#date,#upload,#reviewer1,#email1,#reviewer2,#email2,#reviewer3,#email3)", sqlconn);
sqlcmd.Parameters.AddWithValue("#username", username);
sqlcmd.Parameters.AddWithValue("#title", Text_Title.Text);
sqlcmd.Parameters.AddWithValue("#authors", Text_Author.Text);
sqlcmd.Parameters.AddWithValue("#type", dd_Type.SelectedItem.Text);
sqlcmd.Parameters.AddWithValue("#date", DateTime.Now);
//sqlcmd.Parameters.AddWithValue("#upload", "~/Suppelment/" +
There is no need to pass datetime parameter. Just set a datetime as default value in your table in the Database. That should do the trick.
Here is a link how to set this in table generation script:
How to set the default value for a datetime column
Edit: Your table needs to have a special DateTimeStamp column that will set system-datetime automatically when you insert a record. I am putting a simple script that you may use as an example.
Note: If you already have table in place then just start from script ALTER TABLE
CREATE TABLE [dbo].[Employee]
(
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[BirthDate] [datetime] NOT NULL,
[LastUpdateTime] [datetime] NOT NULL,
CONSTRAINT [PK_Employee]
PRIMARY KEY CLUSTERED ([EmployeeId] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Employee]
ADD CONSTRAINT [DF_Employee_LastUpdateTime]
DEFAULT (getdate()) FOR [LastUpdateTime]
GO
--- You may also use multiple record insert statement in SQL Server 2008
--- however, I will use a traditional approach here
INSERT INTO [dbo].[Employee] (Name, BirthDate)
VALUES ('Smith', '04/14/1979')
INSERT INTO [dbo].[Employee] (Name, BirthDate)
VALUES ('Jhone', '11/08/1983')
GO

SQL SELECT From two tables (friendship) statement

I have the following tables created:
Table #1: tbl_Connections
USE [taaraf_db]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_Connections](
[uc_Id] [int] IDENTITY(1,1) NOT NULL,
[uc_User] [nvarchar](50) NOT NULL,
[uc_Connection] [nvarchar](50) NOT NULL,
[uc_IsPending] [int] NOT NULL,
[uc_DateTime] [datetime] NOT NULL,
CONSTRAINT [PK_tbl_Connections] PRIMARY KEY CLUSTERED
(
[uc_Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tbl_Connections] ADD CONSTRAINT [DF_tbl_Connections_uc_IsPending] DEFAULT ((1)) FOR [uc_IsPending]
GO
Table #2: tbl_LiveStream
USE [taaraf_db]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_LiveStreams](
[ls_Id] [int] IDENTITY(1,1) NOT NULL,
[ls_Story] [nvarchar](max) NOT NULL,
[ls_User] [nvarchar](50) NOT NULL,
[ls_Connection] [nvarchar](50) NOT NULL,
[ls_DateTime] [datetime] NOT NULL,
CONSTRAINT [PK_tbl_LiveStreams] PRIMARY KEY CLUSTERED
(
[ls_Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Now uc_User in tbl_Connections represents the user who initiated a friend request, and uc_Connection
represents the other party.
Same concept is applied on the second table (tbl_LiveStreams)
I am trying to select all new LiveStreams for a cetrain user, LiveStream should be retrieved for a specific user only if that user is connected to the other party (uc_IsPending = 0)
I have a C# function that takes the following arguments:
public static DataTable GetAsyncLiveStream(string CurrentUser, int startAt, int howMany) { ... }
And with the above, a DataTable should return all new items in LiveStream for the given CurrentUser (ls_User) if the requirements specified above are true.
This is sort of like the Facebook news feed, what's happening with friends etc...
Oh yeah, tbl_LiveStream is populated whenever someone (ls_User) initates some sort of specific event to (ls_Connection).
I'm not sure if i'm complicating my life here but that's what I have and all help is appreciated.
I should mention that I've done this by looping through all returned records from tbl_LiveStream and done some validation using a custom class function .IsFriends() that will go and check for friendship status in the database and programatically populates a DataTable... Which is sort of stupid, I admit. But I'm not sure how to do this.
One last thing,
I'm using the following query to return limited results:
SELECT * FROM (
SELECT row_number() OVER (ORDER BY ) AS rownum, ls_Id
FROM )
AS A
WHERE A.rownum BETWEEN (#start) AND (#start + #rowsperpage)
Please help and thank you for your time.
EDIT
I'd like to note that this is how I am fetching who's friends with who from the tbl_Connections Table.
const string sql = "SELECT REPLACE((uc_Connection + uc_User), #CurrentUser, '') AS Connection " +
"FROM tbl_Connections Connection " +
"WHERE (#CurrentUser = uc_Connection) OR (#CurrentUser = uc_User)";
SELECT * FROM (
SELECT row_number() OVER (ORDER BY ) AS rownum, ls_Id
FROM )
AS A
WHERE A.rownum BETWEEN (#start) AND (#start + #rowsperpage)
This syntax is wrong. You can't do it like that. Use a Union, or use LINQ to SQL.
From a critique perspective, don't get DataTables, get Entities. You seem to be over complicating quite a bit here, with technologies you may not be familiar with. I'd advise taking all currently existing data and dumping it to a CSV file, then starting the application from scratch with something like Sharp Architecture, which can abstract away some of these details for you.

Categories