Files retrieved from SQL server FILETABLE are corrupted - c#

I created a FILETABLE on SQL Server 2014 with all the default options with a view for retrieving data and stored procedures for inserting and deleting files. Please note that non-transactional access is not enabled on the database because the files shouldn't be visible on the file system.
The problem is that when I retrieve a file from the table and write it to disk, it isn't identical to the original and can't be opened with the associated program.
Code for the view:
SELECT stream_id, file_stream, name, CAST(creation_time AS DateTime) AS DateCreated, CAST(last_write_time AS DateTime) AS DateUpdated FROM dbo.DocumentFiles
Code for the insert procedure:
create PROCEDURE [dbo].[sp_DocumentFiles_create]
-- Add the parameters for the stored procedure here
#name nvarchar(255),
#data varbinary(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #id uniqueidentifier;
set #id = NEWID();
insert into DocumentFiles (stream_id, file_stream, name) VALUES(#id, #data, #name);
select #id;
END
Code used for reading:
DocumentFile result = null;
SqlCommand comm = new SqlCommand("SELECT * from DocumentView where stream_id = #id", conn);
comm.Parameters.Add(new SqlParameter("#id", id));
try
{
conn.Open();
SqlDataReader reader = comm.ExecuteReader();
while (reader.Read())
{
result = new DocumentFile();
result.stream_id = (Guid)reader["stream_id"];
result.file_stream = (byte[])reader["file_stream"];
result.name = reader["name"].ToString();
result.DateCreated = Convert.ToDateTime(reader["DateCreated"]);
result.DateUpdated = Convert.ToDateTime(reader["DateUpdated"]);
}
}
catch
{
}
finally
{
conn.Close();
}
return result;
Code used for inserting:
public Guid? Insert(DocumentFile obj)
{
Guid? result = null;
SqlCommand comm = new SqlCommand("sp_DocumentFiles_create", conn);
comm.CommandType = System.Data.CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter("#name", obj.name));
comm.Parameters.Add(new SqlParameter("#data", obj.file_stream));
try
{
conn.Open();
result = comm.ExecuteScalar() as Guid?;
}
finally
{
conn.Close();
}
return result;
}
The only files that I managed to insert and retrieve intact are image files. I tried using various ms office documents (.doc, .docx, .pptx, etc) as well as archives (rar, zip).

Related

Stored procedure causing transaction error while executing from C# application

I have the following stored procedure written in SQL database. It executes 2 procedures in different databases. The inner procedures are simple update and insert queries without any explicit TRANSACTION statement applied.
ALTER PROCEDURE [dbo].[usp_1]
#UserID nvarchar(MAX),
#report nvarchar(max),
#sqlErrorMsg nvarchar(MAX) OUTPUT
AS
BEGIN
EXEC #ret = [db1].[dbo].[usp_2]
#user = #UserID,
#msg = #sqlErrorMsg OUTPUT,
#date = #reportDate
set #sqlErrorMsg = 'Report update Status: ' + #sqlErrorMsg
EXEC #ret = [db2].[dbo].[usp_3]
#UserID = #UserID,
#msg = #sqlErrorMsg OUTPUT,
#date = #reportDate
END
This procedure runs perfectly when I execute it in SQL Management studio. But when I run it using a C# code that calls this procedure, I get the following error:
The current transaction cannot be committed and cannot support
operations that write to the log file. Roll back the transaction. The
current transaction cannot be committed and cannot support operations
that write to the log file. Roll back the transaction.
C# Code: (Conn is defined outside with proper connection string and is tested)
public int Upload_Excel_Timer(string userID, string report, out string message)
{
int ret;
SqlCommand cmd = new SqlCommand("usp_1", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserID", userID);
cmd.Parameters.AddWithValue("#report", report);
SqlParameter outputParameter = cmd.Parameters.Add("#sqlErrorMsg", SqlDbType.NVarChar, 255);
outputParameter.Direction = ParameterDirection.Output;
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
try
{
if (conn.State.Equals(ConnectionState.Closed))
conn.Open();
int tempval = cmd.ExecuteNonQuery();
ret = Convert.ToInt32(returnParameter.Value);
message = outputParameter.Value.ToString();
}
catch (Exception e)
{
ret = -1;
message = e.Message;
}
finally
{
conn.Close();
}
return ret;
}

Inserting data into SQL Server by using a stored procedure

I have a problem while inserting records into SQL Server.
The string from C# doesn't show up in SQL Server as I'm inserting the sql just insert the first char
Example: If I insert 22222 in the data base just the first 2 inserted
Note I'm using a stored procedure for my first time.
This is my code:
public void insert_workshop(DateTime Pdate, string PTime, string PDesc, byte[] Img)
{
SqlCommand cmd = new SqlCommand("[InsertWorkShops]", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#WorkshopsDate", SqlDbType.Date).Value = Pdate;
cmd.Parameters.Add("#Time", SqlDbType.NVarChar).Value = PTime;
cmd.Parameters.Add("#WorkshopsDescription", SqlDbType.NVarChar).Value = PDesc;
cmd.Parameters.Add("#WorkshopsImage", SqlDbType.Image).Value = Img;
cmd.Parameters.Add("#CreatedBy", SqlDbType.NVarChar).Value = 1;
try
{
cmd.ExecuteNonQuery();
Msg = "Add Done ";
}
catch
{
Msg = "Error While Adding";
}
WorkShopTransactions Ws = new WorkShopTransactions();
Ws.insert_workshop(WorkShopDT.Value, txtWorshopTime.Text.ToString(),
txtWorkshopDescriptions.Text.ToString(), img);
T-SQL:
ALTER PROCEDURE [dbo].[InsertWorkShops]
#WorkshopsDate date,
#Time nvarchar,
#WorkshopsDescription nvarchar,
#WorkshopsImage image,
#CreatedBy int
AS
BEGIN
SET NOCOUNT ON;
insert into Workshops
values(#WorkshopsDate, #Time, #WorkshopsDescription, #WorkshopsImage, #CreatedBy)
END
In the stored procedure, you have declared your nvarchar parameters without a length. They default to nvarchar(1).

Convert to stored procedure

How I will save this to stored procedure? And run the stored procedure in c#?
string a = "Select * from EmpTable Where EmpName Like #SearchItem";
using (SqlCommand SqlCommand = new SqlCommand(" "+ a +" ", myDatabaseConnection))
{
SqlCommand.Parameters.AddWithValue("#SearchItem", "%" + textBox1.Text + "%");
}
Stored procedure:
CREATE PROCEDURE SearchSP
#SearchItem nvarchar(MAX)
AS
BEGIN
Select *
from EmpTable
Where EmpName Like '%' + #SearchItem + '%'
END
GO
Code:
using (SqlCommand cmd= new SqlCommand("SearchSP", myDatabaseConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#SearchItem", textBox1.Text);
//rest of the code
}
What your Saying is you want the string gone and to call a stored procedure instead that has this SQL code inside? If that's the case..
Presuming SQL server 2008 management studio..
In management studio expand your "database", Then Expand "Programmability"...
Right click create new stored procedure and delete all code inside.
then type in the following.
USE [YourDataBaseName]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[AnyName]
#SearchItem as nvarchar(MAX)
AS
Select * from EmpTable Where EmpName Like #SearchItem
click run/execute and refresh your database, if you look in the stored proc folder you should see your new stored procedure.
Then in your (presuming C#.Net) code.
public string GetUserFinal(string _userInput)
{
string temp = "";
using (SqlConnection myConn = new SqlConnection(Conn))
{
using (SqlCommand myCommand = new SqlCommand())
{
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.CommandText = "dbo.your procedure name";
myCommand.Parameters.AddWithValue("#SearchItem", _userInput);
SqlDataReader reader = myCommand.ExecuteReader();
myCommand.Connection = myConn;
While (reader.read())
{
//populate a string? or do something else?
}
}
}
return temp;
}
A better way would be to Strongly type all of this. So i would create a Model of whatever you now the fields and types will be, then create a list And iterate through that list to bind from this Function. But as you can see the basics, this should work just check the syntax.
Create a stored procedure something like below:
Create Procedure dbo.Test
#SearchItem
AS
BEGIN
BEGIN TRY
IF EXISTS(SELECT 1 FROM dbo.Table WHERE EmpName LIKE '%'+#SearchItem+'%')
SELECT * FROM dbo.Table WHERE EmpName LIKE '%'+#SearchItem+'%'
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS 'ErrorNumber', ERROR_MESSAGE() AS 'ErrorMessage', ERROR_SEVERITY() AS 'ErrorSeverity', ERROR_STATE() AS 'ErrorState', ERROR_LINE() AS 'ErrorLine'
RETURN ERROR_NUMBER()
END CATCH
END
Now you can refer this sp in code-behind as below:
SqlConnection xconn=new SqlConnection(Write your connection string);
SqlCommand xcommand=new SqlCommand("Test",xconn);
xcommand.CommandType=CommandType.StoredProcedure;
xcommand.Parameters.AddWithValue("#SearchItem",DbType.String,txtBox1.Text);
xconn.Open();
xCommand.ExecuteNonQuery();
xconn.Close();
this will be your stored proc, (haven't tested the code):
CREATE PROCEDURE TestStoredProc
#SearchItem nvarchar(MAX)
AS
BEGIN
SET NOCOUNT ON;
Select *
from EmpTable
Where EmpName Like '%' + #SearchItem + '%'
END
GO
Then in code side do this:
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand("TestStoredProc", conn) {
CommandType = CommandType.StoredProcedure, Parameters.AddWithValue("#SearchItem",textbox.Text)}) {
}

C# SQL stored procedure (which inserts) - pass parameters and retrieve parameter

I have a stored procedure on my server that inserts some parameters and returns the ID that was inserted. I am writing a form to do this easily but I cannot seem to get the parameter which is passed back.
To save you doing a whole bunch of possibly pointless reading, it's probably better to just pay attention to my C# code and let me know what I need to do in order to pass parameters and get one in return.
C# Default.aspx
connection = new SqlConnection(ConfigurationManager.AppSettings["ConnectionInfo"]);
sql = "aStoredProc";
command = new SqlCommand(sql, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameter.Add(new SqlParameter("#FirstName", SqlDbType.VarChar)).Value = sFirstname;
command.Parameter.Add(new SqlParameter("#SurName", SqlDbType.VarChar)).Value = sSurname;
connection.Open();
int ID = command.ExecuteNonQuery();
connection.Close();
SQL aStoredProc
IF EXISTS(SELECT * FROM aTable WHERE ID = #ID)
-- User exists, update details
BEGIN
BEGIN TRAN
UPDATE aTable
SET
FirstName = #FirstName,
SurName = #SurName,
LastUpdate = GetDate()
WHERE ID = #ID
IF (##Error != 0)
ROLLBACK TRAN
ELSE
COMMIT TRAN
END
ELSE
-- New user
BEGIN
BEGIN TRAN
INSERT aTable (
FirstName,
SurName,
GetDate()
)
VALUES (
#FirstName,
#SurName,
#LastUpdate
)
SELECT #ID = ##IDENTITY
IF (##Error != 0)
ROLLBACK TRAN
ELSE
COMMIT TRAN
END
The parameter #ID is listed in the stored proc as:
#ID (int, Input/Output, No default)
and proc has 'Return integer'. This used to work fine with a VBA solution prior to a SQL Server 2005 upgrade.
Thanks in advance.
connection = new SqlConnection(ConfigurationManager.AppSettings["ConnectionInfo"]);
sql = "aStoredProc";
command = new SqlCommand(sql, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameter.Add(new SqlParameter("#FirstName", SqlDbType.VarChar)).Value = sFirstname;
command.Parameter.Add(new SqlParameter("#SurName", SqlDbType.VarChar)).Value = sSurname;
command.Parameter.Add(new SqlParameter("#SurName", SqlDbType.VarChar)).Value = sSurname;
SqlParameter ParamId = cmd.Parameters.Add( "#Id", SqlDbType.Int);
ParamId.Direction = ParameterDirection.InputOutput;
command.Parameter.Add(ParamId);
connection.Open();
command.ExecuteNonQuery();
int ID = ParamId.Value;
connection.Close();
you have to add output paramter in Parameter collection.
Read Value like above.
You have an error in your SQL, it should look like this:
INSERT aTable (FirstName,SurName,LastUpdate)
VALUES (#FirstName, #SurName, GetDate() )
Not like this:
INSERT aTable (
FirstName,
SurName,
GetDate()
)
VALUES (
#FirstName,
#SurName,
#LastUpdate
)

How to modify Stored Procedure or ASP.net Code to get autogenerated Id after inserting new row

I m creating new user registration moduleand for that i wrote following stored proc.
PROCEDURE [dbo].[addNewUser]
-- Add the parameters for the stored procedure here
#usertype VarChar(10),
#useremail VarChar(70),
#userpass VarChar(20),
#fullname VarChar(70),
#city VarChar(70),
#state Int,
#allowAlerts Bit,
#allowLetter Bit,
#aboutMe NVARCHAR(160)
As
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if ((select count(user_info._id) from user_info where useremail like #useremail) = 0)
BEGIN
Insert Into user_info
(usertype,useremail,userpass,fullname,city,[state],allowAlerts,allowLetters,aboutMe)
Values
(
#usertype,
#useremail,
#userpass ,
#fullname,
#city,
#state,
#allowAlerts,
#allowLetter,
#aboutMe
)
Select ##IDENTITY as NewID
END
Else
BEGIN
Print '-1'
END
And following is the simple ASP.net C# Code that I try to use
public int registerNewUser(string usertype, string useremail, string userpass, string fullname, string city, string state, string allowAlerts, string allowLetter, string aboutMe)
{
con = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "addBlogEntry";
cmd.Parameters.Add("#usertype", SqlDbType.VarChar).Value = usertype;
cmd.Parameters.Add("#useremail", SqlDbType.VarChar).Value = useremail;
cmd.Parameters.Add("#userpass", SqlDbType.VarChar).Value = userpass;
cmd.Parameters.Add("#fullname", SqlDbType.VarChar).Value = fullname;
cmd.Parameters.Add("#city", SqlDbType.VarChar).Value = city;
cmd.Parameters.Add("#state", SqlDbType.VarChar).Value = Convert.ToInt16(state);
cmd.Parameters.Add("#allowAlerts", SqlDbType.VarChar).Value = Convert.ToInt16(allowAlerts);
cmd.Parameters.Add("#allowLetter", SqlDbType.VarChar).Value = Convert.ToInt16(allowLetter);
cmd.Parameters.Add("#aboutMe", SqlDbType.VarChar).Value = aboutMe;
try
{
if (con.State != ConnectionState.Open)
con.Open();
cmd.ExecuteNonQuery();
con.Close();
con.Dispose();
// some code to be written here so that i can return userID(success) or -1(if that username is already registered)
return 0;
}
catch (Exception Ex)
{
con.Close();
con.Dispose();
return 0;
}
}
Through my C# code i want to return either auto generated userId which my stored procedures returns to me or if user alrady exists than i want to return -1
Please tell how to do this?
Thanks in advance :)
Yes, you can use ExecuteScalar() and change
Print '-1'
into
Select -1 as NewID
First of all, you should use SELECT SCOPE_IDENTITY() inside your stored proc to retrieve the new ID value (##IDENTITY can return false results).
And yes, if you want to get the result back, you need to call either .ExecuteScalar() or .ExecuteReader() and then read that value back.
And while you're at it - I'd also recommend putting your SqlConnection and SqlCommand objects into using blocks - so instead of your code, use this:
using(con = new SqlConnection(connectionString))
using(cmd = new SqlCommand(con))
{
..... // put the rest of your code here
}
If you want to create an output parameter for your stored proc, and set it to the new key you can access it that way. ExecuteNonQuery will return the number of rows affected, so that can be used as well. Something like this:
cmd.Parameters.Add("#uniquID", SqlDbType.Int).Direction = ParameterDirection.Output;
// Your other code...
var result = cmd.ExecuteNonQuery();
// Your other code...
return (result == 1) ? (int)cmd.Parameters["#uniquID"].Value : -1;

Categories

Resources