TVP does not conform to table type - sql-server

Below is the function that inserts my data.
using (SqlCommand insSwipeDataCommand = connection.CreateCommand())
{
insSwipeDataCommand.Transaction = transaction;
insSwipeDataCommand.CommandType = CommandType.StoredProcedure;
insSwipeDataCommand.CommandText = "dbo.insSwipeData_sp";
SqlParameter attendeeTableParam = insSwipeDataCommand.Parameters.Add("#AttendeeTable", SqlDbType.Structured);
attendeeTableParam.Value = this.dataTable;
attendeeTableParam.TypeName = "AttendeeTableType";
// add orgid parameter
insSwipeDataCommand.Parameters.Add("#orgId", SqlDbType.UniqueIdentifier).Value = this.organizationId;
insSwipeDataCommand.ExecuteNonQuery();
}
insSwipeData_sp
create PROC dbo.insSwipeData_sp
(#AttendeeTable AttendeeTableType READONLY
,#orgId UNIQUEIDENTIFIER
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #enteredUserId UNIQUEIDENTIFIER
SET #enteredUserId = 'xxxxxxxxx-xxxx-xxx-xxxx-xxxxxxxxxx'
-- Delete old Swipe records
DELETE FROM dbo.swipeData_tbl
WHERE orgId = #orgId
-- CREATE Swipe Records
INSERT INTO dbo.swipeData_tbl
(orgId, sdid, rawData, enteredUserId, enteredUtc, manualEntry)
SELECT #orgId, attendeeId, barcode
,#enteredUserId, GETUTCDATE(), 0 -- Consider ( datepart , date ) if date here is needed as NVARCHAR
FROM #AttendeeTable
WHERE barcode IS NOT NULL and LTRIM(RTRIM(barcode)) <> '';
END
Here is an image of my AttendeeTableType schema.
and here is an image of my this.datatable that i am using for my attendeeTableParam
On the insSwipeDataCommand.ExecuteNonQuery(); line i get the following error.
The data for table-valued parameter "#AttendeeTable" doesn't conform to the table type of the parameter.

Per the error, your data does not conform to the table type exactly. Note "exactly" -- if you do not specify types for the columns, they will be inferred, and they can easily be inferred incorrectly. The best approach here is to create a table that you know matches the table type definition:
var dt = new DataTable();
dt.Columns.Add("firstName", typeof(string)).MaxLength = 100;
dt.Columns.Add("lastName", typeof(string)).MaxLength = 100;
dt.Columns.Add("studentId", typeof(string)).MaxLength = 10;
dt.Columns.Add("email", typeof(string)).MaxLength = 100;
dt.Columns.Add("barcode", typeof(string)).MaxLength = 100;
dt.Columns.Add("dob", typeof(string)).MaxLength = 200;
dt.Columns.Add("major", typeof(string)).MaxLength = 200;
dt.Columns.Add("gender", typeof(string)).MaxLength = 200;
dt.Columns.Add("classCode", typeof(string)).MaxLength = 15;
dt.Columns.Add("currentclassCode", typeof(string)).MaxLength = 15;
dt.Columns.Add("entranceCode", typeof(string)).MaxLength = 15;
dt.Columns.Add("attendeeId", typeof(Guid));
And then use .Clone() to create a new table with the correct schema when you need to insert data. This way, if you have a type or length mismatch, it will be caught on the client end.
There is another approach you can take that does not rely on embedding the table definition into the application, which is fetching it from the database. There are pros and cons to this -- it requires an extra roundtrip to the database and it's not as easy to spot mistakes in the application logic if the types or columns don't match, but it does give you additional flexibility to change the type without having to change the application (adding a new, nullable column, for example).
var dt = new DataTable();
using (var connection = new SqlConnection(...)) {
connection.Open();
using (var command = new SqlCommand()) {
command.Connection = connection;
command.CommandText = "DECLARE #t dbo.AttendeeTableType; SELECT * FROM #t;"
using (var reader = command.ExecuteReader()) {
dt.Load(reader);
}
}
}
Obviously you probably want to cache the results of this and .Clone(), rather than doing it for every command involving the table type parameter.

I reached this page while searching for similar issue that I was experiencing, but none of the replies did help me. After some head beating I found that the error is being generated in case when the data table being passed from the code has some data that does not match the TVP type specification.
For example if you defined the following type:
CREATE TYPE EmployeeType AS TABLE
(
EmpID BigInt, EmpName VARCHAR(100)
)
and suppose the data table that you are passing has (say) one EmpName that has more than 100 characters then "*** does not conform to table type" error is generated.
This solved my issue. Hope it will help others as well.

Even though Jeroen Mostert answer helped me solve one piece of the puzzle, this error was still popping up.
Here is what I learned;
Datatable created and passed as table value param should
correspond to the sequence / order of field in table value type defined
in sql.
So if your table type looks like below :
CREATE TYPE [dbo].[tvp_mytabletype] AS TABLE(
[ID] BIGINT,
[AddressCode] BIGINT,
[Address] NVARCHAR(200) NOT NULL
)
then define your DT with columns in exact same order/sequence like below :
DataTable dataTable = new DataTable();
//DataTable definition
dataTable.Columns.Add("ID", typeof(long));
dataTable.Columns.Add("AddressCode", typeof(long));
dataTable.Columns.Add("Address", typeof(string)).MaxLength = 200;

Your attendeeId is looks strange. It must be Guid in C# side.

Related

snowflake jdbc paramter returning VARCHAR for all datatypes

Snowflake JDBC driver is reporting parameter metadata for all the datatypes as VARCHAR. Is there any way to overcome this problem?
DDL:-
CREATE TABLE INTTABLE(INTCOL INTEGER)
Below is the output from Snowflake ODBC Driver
SQLPrepare:
In:StatementHandle = 0x00000000021B1B50, StatementText = "INSERT INTO INTTABLE(INTCOL) VALUES(?)", TextLength = 42
Return: SQL_SUCCESS=0
SQLDescribeParam:
In:StatementHandle = 0x00000000021B1B50, ParameterNumber = 1, DataTypePtr = 0x00000000001294D0, ParameterSizePtr = 0x0000000000126950,DecimalDigits =0x0000000000126980, NullablePtr = 0x00000000001269B0
Return: SQL_SUCCESS=0
Out:*DataTypePtr = SQL_VARCHAR=12, *ParameterSizePtr = 16777216, *DecimalDigits = 0, *NullablePtr = SQL_NULLABLE=1
Below is Output with Snowflake JDBC Driver.
PreparedStatement ps = c.prepareStatement("INSERT INTO INTTABLE(INTCOL) VALUES(?)");
ParameterMetaData psmd = ps.getParameterMetaData();
for(int i=1 ;i<=psmd.getParameterCount(); i++) {
System.out.println(psmd.getParameterType(i)+ " " + psmd.getParameterTypeName(i));
}
Output:-
12 text
Thank you for adding more information to your thread. I still may be doing a little guesswork though.
If you are trying to change the table values type from Varchar, and there are no values in it, you can drop the table, then re-recreate it.
If you want to ALTER what is already in the table try altering the table first: Manual Reference
There is also the CREATE OR REPLACE TABLE(col , col 2 ) that takes care of both.
Is this what you are looking for?

How to check that any particular record already exist in the database or not before inserting record in MVC?

I am using the following code to export data from excel to Sql server database. What is going on with this code is, its importing complete data into the database.
[HttpPost]
public ActionResult Importexcel()
{
if (Request.Files["FileUpload1"].ContentLength > 0)
{
string extension = System.IO.Path.GetExtension(Request.Files["FileUpload1"].FileName);
string path1 = string.Format("{0}/{1}", Server.MapPath("~/Content/UploadedFolder"), Request.Files["FileUpload1"].FileName);
if (System.IO.File.Exists(path1))
System.IO.File.Delete(path1);
Request.Files["FileUpload1"].SaveAs(path1);
string sqlConnectionString = #"Data Source=xyz-101\SQLEXPRESS;Database=PracDB;Trusted_Connection=true;Persist Security Info=True";
string excelConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path1 + ";Extended Properties=Excel 12.0;Persist Security Info=False";
OleDbConnection excelConnection = new OleDbConnection(excelConnectionString);
OleDbCommand cmd = new OleDbCommand("Select [ID],[Name],[Designation] from [Sheet1$]", excelConnection);
excelConnection.Open();
OleDbDataReader dReader;
dReader = cmd.ExecuteReader();
SqlBulkCopy sqlBulk = new SqlBulkCopy(sqlConnectionString);
sqlBulk.DestinationTableName = "Excel_Table";
sqlBulk.WriteToServer(dReader);
excelConnection.Close();
}
return RedirectToAction("Index");
}
How to check that any particular record already exist in the database or not. If not then Insert the record into the databse else it should not.
Thanks in Advance !
Since your target is SQL Server, you can use this to your advantage.
What I would do is read the data from the excel into a DataTable (instead of using a DataReader you can use a DataAdapter), Send that DataTable to a stored procedure in the SQL server, and handle the insert there. In order to sand a data table to a stored procedure you first need to create a Table-value user defined type in your sql server, like this:
CREATE TYPE MyType AS TABLE
(
Id int,
Name varchar(20), -- use whatever length best fitted to your data
Designation varchar(max) -- use whatever length best fitted to your data
)
Then you can write a simple stored procedure with an argument of this type:
CREATE PROCEDURE InsertDataFromExcel
(
#ExcelData dbo.MyType readonly -- Note: readonly is a required!
)
AS
INSERT INTO MyTable(Id, Name, Designation)
SELECT a.Id, a.Name, a.Designation
FROM #ExcelData a LEFT JOIN
MyTable b ON(a.Id = b.Id)
WHERE b.Id IS NULL -- this condition with the left join ensures you only select records that has different id values then the records already in your database
in order to send this parameter to the stored procedure from your c# code you will have to use a SqlCommand object and add the DataTable as a parameter, something like this:
using(SqlConnection Con = new SqlConnection(sqlConnectionString))
{
using(SqlCommand InsertCommand = new SqlCommand("InsertDataFromExcel", Con))
{
SqlParameter MyParam = new SqlParameter("#ExcelData", SqlDBType.Structured);
MyParam.Value = MyDataTable; // this is the data table from the
InsertCommand.Parameters.Add(MyParam);
Con.Open();
InsertCommand.ExecuteNoQuery();
Con.Close();
}
}
Note: Code was writen directly here, some errors might be found.

Invalid Object Name, Temporary Table Entity Framework

I´m trying to optimize some process in my application but I´m stuck with this problem. My application is working so the entity mapping is correct. Simplifying what I´m trying to do is this:
using (var offCtx = new CheckinOfflineEntities())
{
using (var trans = offCtx.Database.BeginTransaction(IsolationLevel.Snapshot))
{
DateTime purgePivot = DateTime.Now.AddDays(-2);
count = offCtx.Database.ExecuteSqlCommand(#"select L.* into #NewLegs from InventoryLeg L where L.STDUTC >= {0}", purgePivot);
long d = offCtx.Database.SqlQuery<long>("select count(*) from #NewLegs").FirstOrDefault();
}
}
I´m selecting some data I want to delete from one table, storing it in a temporary table so that I can use this temporary table in other queries to exclude related data.
The problem is, when I try to use the temporary table I´m receiving the exception SqlException: "Invalid object name '#NewLegs'."
Thank you for your time.
You can merge the query like this.
And count returns int, not long.
COUNT always returns an int data type value. - MSDN
var query = string.Format("{0} {1}",
#"select L.* into #NewLegs from InventoryLeg L where L.STDUTC >= #STDUTC",
#"select count(*) from #NewLegs")
var d = offCtx.Database.SqlQuery<int>(query, new SqlParameter("STDUTC", purgePivot))
.FirstOrDefault();
I realy don´t know why but removing the parameter and adding it in the query solved the problem.
The code below works fine:
using (var offCtx = new CheckinOfflineEntities())
{
using (var trans = offCtx.Database.BeginTransaction(IsolationLevel.Snapshot))
{
DateTime purgePivot = DateTime.Now.AddDays(-2);
count = offCtx.Database.ExecuteSqlCommand(#"select L.* into #NewLegs from InventoryLeg L where L.STDUTC >= " + purgePivot.toString("yyyy-mm-dd HH:mm:ss");
long d = offCtx.Database.SqlQuery<long>("select count(*) from #NewLegs").FirstOrDefault();
}
}

how to overwrite repeat data in the database in a efficient way?

I use Sql server 2008 to store my data,and the table structure like that
index float not null,
type int not null,
value int not null,
and the (index,type) is unique.there are not two datas has the same index and the same type.
So when I insert the data to the table, I have to check the (index,type) pair whether in the table already, if it exists I use update statement, otherwise, I insert it directly.but I think this is not a efficient way,because:
Most of the data' index-type pair is not existed int the table.so the select operation is waste, especially the table is huge.
When I use C# or other CLR language to insert the data, I can't use batch copy or batch insert.
is there any way to overwrite the data directly without check whether it is existed in the table?
If you want to update OR insert the data, you need to use merge:
merge MyTable t using (select #index index, #type type, #value value) s on
t.index = s.index
and t.type = s.type
when not matched insert (index, type value) values (s.index, s.type, s.value)
when matched update set value = s.value;
This will look at your values and take the appropriate action.
To do this in C#, you have to use the traditional SqlClient:
SqlConnection conn = new SqlConnection("Data Source=dbserver;Initial Catalog=dbname;Integrated Security=SSPI;");
SqlCommand comm = new SqlCommand();
conn.Open();
comm.Connection = conn;
//Add in your values here
comm.Parameters.AddWithValue("#index", index);
comm.Parameters.AddWithValue("#type", type);
comm.Parameters.AddWithValue("#value", value);
comm.CommandText =
"merge MyTable t using (select #index index, #type type, #value value) s on " +
"t.index = s.index and t.type = s.type " +
"when not matched insert (index, type value) values (s.index, s.type, s.value) " +
"when matched update set value = s.value;"
comm.ExecuteNonQuery();
comm.Dispose();
conn.Close();
conn.Dispose();
You should make (index, type) into a composite primary key (aka compound key).
This would ensure that the table can only even have unique pairs of these (I am assuming the table does not have a primary key already).
If the table does have a primary key, you can add a UNIQUE constraint onto those columns with similar effect.
Once defined, this means that any attempt to insert a duplicate pair would fail.
Other answers recommend constraints. Creating constraints just means you will be executing insert statements that trigger errors. The next step (after having created the constraints) is something like INSERT ON DUPLICATE KEY UPDATE, which apparently does have an Sql Server equivalent.

EF ExecuteStoredCommand with ReturnValue parameter

I'm creating a new application which needs to interface with legacy code :(.
The stored procedure I'm attempting to call uses RETURN for its result. My attempts to execute and consume the return value result in the exception:
InvalidOperationException: When executing a command, parameters must be exclusively database parameters or values.
Changing the stored proc to return the value another way isn't desired, since it either requires updating the legacy app or maintaining a nearly duplicate stored proc.
The legacy stored proc synopsis:
DECLARE #MyID INT
INSERT INTO MyTable ...
SELECT #MyID = IDENTITY()
RETURN #MyID
My Entity Framework / DbContext work, which yields the above InvalidOperationException.
SqlParameter parm = new SqlParameter() {
ParameterName = "#MyID",
Direction = System.Data.ParameterDirection.ReturnValue
};
DbContext.Database.ExecuteSqlCommand("EXEC dbo.MyProc", parm);
Looking for any and all solutions which don't require the stored proc to be modified.
You can capture the return value of the stored procedure into an output parameter instead:
SqlParameter parm = new SqlParameter() {
ParameterName = "#MyID",
SqlDbType = SqlDbType.Int,
Direction = System.Data.ParameterDirection.Output
};
Database.ExecuteSqlCommand("exec #MyId = dbo.MyProc", parm);
int id = (int)parm.Value;
I know it's a bit late, but this works for me:
var param = new SqlParameter("#Parameter1", txtBoxORsmth.text);
someVariable = ctx.Database.SqlQuery<int>("EXEC dbo.MyProc", param).First();
You don't have to use ExecuteSqlCommand.
You can just get the underlying connection from DbContext.Database.Connection and use raw ADO.NET (CreateCommand(), ExecuteNonQuery(), ...)
The error message
InvalidOperationException: When executing a command, parameters must be exclusively database parameters or values.
means that you're not providing the right type (or something else which isn't shown in your code snippet) in the params list of SQLParameters.
In my case I had forgotten to remove a MergeOption because I changed the way the SQL command was executed.
This extension method will do all the dirty work for you now. See fuller description on SO here.
This will return the int from a stored proc using DBContext:
var newId = DbContext.Database.SqlQuery<int>("EXEC dbo.MyProc #MyID = {0}", parm).First();
Create table for With parameter example for testing or change the second sql query according to yours.
CREATE TABLE [dbo].[Test](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Test] 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]
//========================= =================================//
public void Test()
{
using (var db = new DbContext())
{
string sql = "dbo.MyProc"; //With Out Parameter
int id1 = (int)db.Database.SqlQuery<decimal>(sql).FirstOrDefault();
db.SaveChanges();
//Or
sql = "INSERT Test(Name) values({0}) SELECT SCOPE_IDENTITY();"; //With Parameter
int id2 = (int)db.Database.SqlQuery<decimal>(sql, new object[] { "Thulasi Ram.S" }).FirstOrDefault();
db.SaveChanges();
}
}
I tried the ways above, but only this way works out for me(Must have the 'ToList()' function):
SqlParameter res = new SqlParameter()
{
ParameterName = "Count",
Value=1,
Direction = System.Data.ParameterDirection.Output
};
db.Database.SqlQuery<object>(
"[dbo].[GetWorkerCountBySearchConditions] #Count ,
res
).ToList();
return Convert.ToInt32(res.Value);
I'm sure this isn't the only valid answer, but one that I ultimately used and has been working successfully.
The key seemed to be naming the ReturnValue parameter RetVal.
SqlParameter id = create.Parameters.Add("RetVal", System.Data.SqlDbType.Int);
id.Direction = System.Data.ParameterDirection.ReturnValue;
putting it all together:
SqlCommand proc = new SqlCommand("dbo.MyProc", new SqlConnection(<connection string>));
proc.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter id = create.Parameters.Add("RetVal", System.Data.SqlDbType.Int);
id.Direction = System.Data.ParameterDirection.ReturnValue;
proc.ExecuteNonQuery();
int newId = Convert.ToInt32(id.Value);

Resources