im trying to use a jquery plugin to upload my images and insert it into my database.
my problem are the relationship i have between the two table.
The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_Image_User". The conflict occurred in database
"Mydatabase", table "dbo.User", column 'Id'.
here is my code:
in controller:
GET:
public ActionResult Manage(int id = 0)
{
User u= db.MyUsers.Find(id);
if (u== null)
{
return HttpNotFound();
}
return View(u);
}
To upload i have this code:
private void UploadWholeFile(HttpContext context, List<FilesStatus> statuses, Image img, User u)
{
using (SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
for (int i = 0; i < context.Request.Files.Count; i++)
{
var file = context.Request.Files[i];
var fullpath = StorageRoot + Guid.NewGuid() + Path.GetFileName(file.FileName);
file.SaveAs(fullpath);
string fullName = Path.GetFileName(file.FileName);
statuses.Add(new FilesStatus(fullName, file.ContentLength, fullpath));
SqlCommand cmd;
System.Text.StringBuilder sql = new System.Text.StringBuilder();
sql.Append("insert into Image(MyFileName,Id_User)");
sql.Append("values (#MyFileName, #Id_User)");
cn.Open();
cmd = new SqlCommand(sql.ToString(), cn);
cmd.Parameters.Add("#MyFileName", SqlDbType.VarChar).Value = fullpath;
cmd.Parameters.Add("#Id_User", SqlDbType.Int).Value = u.Id;
cmd.ExecuteNonQuery();
cn.Close();
}
}
}
Id_User is in a foreign key relationship with dbo.User table, which does not contain the ID you are trying to insert. Insert the value in the dbo.User table first, or check and correct the value you are inserting in Id_User.
Related
I have a class named ImageData who contains a list of Tags
I get the database locked error only if an image has more than 1 tag and I can't find out why
0 tag and 1 tag is always fine, with 1 image or a 100.
As soon as 1 image has 2 tags, I get the error
I make sure of disposing of everything with the using statement
here is the method
public static int addImages(List<ImageData> images)
{
int rows = 0;
using (SQLiteConnection con = new SQLiteConnection(ConnectionString()))
{
con.Open();
foreach (ImageData img in images)
{
using (SQLiteCommand cmd = new SQLiteCommand($"INSERT INTO images(Hash, Extension, Name) VALUES(#IHash,#IExtension, #IName)", con))
{
cmd.Parameters.AddWithValue("#IHash", img.Hash);
cmd.Parameters.AddWithValue("#IExtension", img.Extension);
cmd.Parameters.AddWithValue("#IName", img.Name);
rows += cmd.ExecuteNonQuery();
}
foreach (Tag tag in img.Tags)
{
using (SQLiteCommand cmd = new SQLiteCommand($"INSERT INTO ImagesTags(ImageHash, TagName) VALUES(#IHash,#IName)", con))
{
cmd.Parameters.AddWithValue("#IHash", img.Hash);
cmd.Parameters.AddWithValue("#IName", tag.Name);
cmd.ExecuteNonQuery();
}
}
}
con.Close();
}
return rows;
}
here are my tables Creation
string[] createTable =
{
"CREATE TABLE images(Hash TEXT PRIMARY KEY, Extension TEXT, Name TEXT)",
"CREATE TABLE tags(NAME TEXT PRIMARY KEY NOT NULL,DESCRIPTION TEXT,COLLECTIONNAME TEXT)",
"CREATE TABLE ImagesTags(ImageHash TEXT,TagName TEXT,Primary KEY (ImageHash, TagName),FOREIGN KEY (ImageHash) REFERENCES images(Hash),FOREIGN KEY (TagName) REFERENCES tags(Name))"
};
There are multiple cases where I insert data in a foreach loop and this is the only place where I get this error.
After googling quite a lot I learned about cleaner ways of working with sqlite.
The probleme was fixed by using using statement for every connections, commands, transactions and readers.
something somewhere must have been incorrectly disposed
here is the same function as before but with better coding
I also added transactions to make only 1 call to the database and allow a rollback if something went wrong
public static int addImages(List<ImageData> images)
{
int rows = 0;
using (var con = new SQLiteConnection(ConnectionString()))
{
con.Open();
using (var tra = con.BeginTransaction())
{
try
{
foreach (ImageData img in images)
{
SQLiteParameter p1 = new SQLiteParameter("#IHash", System.Data.DbType.String);
SQLiteParameter p2 = new SQLiteParameter("#IExtension", System.Data.DbType.String);
SQLiteParameter p3 = new SQLiteParameter("#IName", System.Data.DbType.String);
using (SQLiteCommand cmd = new SQLiteCommand($"INSERT INTO images(Hash, Extension, Name) VALUES(#IHash,#IExtension, #IName)", tra.Connection))
{
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
cmd.Parameters.Add(p3);
p1.Value = img.Hash;
p2.Value = img.Extension;
p3.Value = img.Name;
cmd.ExecuteNonQuery();
}
foreach (Tag tag in img.Tags)
{
using (SQLiteCommand cmd = new SQLiteCommand($"INSERT INTO ImagesTags(ImageHash, TagName) VALUES(#IHash,#IName)", tra.Connection))
{
cmd.Parameters.AddWithValue("#IHash", img.Hash);
cmd.Parameters.AddWithValue("#IName", tag.Name);
cmd.ExecuteNonQuery();
}
}
}
tra.Commit();
}
catch(Exception ex)
{
tra.Rollback();
throw;
}
}
}
return rows;
}
I want to insert a PNG image into an OracleDatabase using OleDb and a C# application. The table looks like this:
CREATE TABLE Plant
(
Id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
Name VARCHAR2(50) NOT NULL,
Image BLOB null,
CONSTRAINT plant_pk PRIMARY KEY (Id)
);
Below is the code:
public static void AddBinaryParameterToCommand(OleDbCommand cmd, string parameterColumn, object parameter)
{
if (cmd != null)
{
if (parameter != null && !parameter.ToString().Equals(""))
{
OleDbParameter blobParameter = new OleDbParameter();
blobParameter.OleDbType = OleDbType.LongVarBinary;
blobParameter.Direction = ParameterDirection.InputOutput;
blobParameter.ParameterName = parameterColumn;
blobParameter.Value = parameter;
cmd.Parameters.Add(blobParameter);
}
else
cmd.Parameters.Add(new OleDbParameter(parameterColumn, DBNull.Value));
}
}
public int InsertPlant(string name, byte[] image)
{
int id = 0;
using (var connection = new OleDbConnection(ConnectionString))
{
var commandGetIdText = #"SELECT MAX(id) FROM PLANT";
connection.Open();
using (var command = new OleDbCommand(commandGetIdText, connection))
{
using (var reader = command.ExecuteReader())
{
reader.Read();
id = int.Parse(reader[0].ToString()) + 1;
}
}
var commandText = string.Format("INSERT INTO PLANT(ID,NAME,IMAGE) VALUES (?, ?, ?)");
using (var command = new OleDbCommand(commandText, connection))
{
Utils.AddParameterToCommand(command, "ID", id);
Utils.AddParameterToCommand(command, "NAME", name);
Utils.AddBinaryParameterToCommand(command, "IMAGE", image);
command.ExecuteNonQuery();
connection.Close();
}
}
return id;
}
private void button_UploadMap_Click(object sender, EventArgs e)
{
var openFileDialog = new OpenFileDialog
{
Multiselect = true
};
var path = string.Empty;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
path = openFileDialog.FileName;
}
else
{
return;
}
byte[] imageArray = File.ReadAllBytes(path);
var palletMapDL = new PalletMapDL("Data Source=192.168.1.21/orcl;Persist Security Info=True; Password=test;User ID=test; Provider=MSDAORA; OLEDB.NET=True; PLSQLRSet=1");
palletMapDL.InsertPlant("Test Plant 01", imageArray);
When execute command.ExecuteNonQuery(); I got this error message:
System.InvalidOperationException: 'Command parameter[2] '' data value
could not be converted for reasons other than sign mismatch or data
overflow.
OleDbException: 'MSDAORA' failed with no error message available,
result code: DB_E_ERRORSOCCURRED(0x80040E21).
Do you know what could be the issue?
Thanks
I've been having trouble (again) with some object-oriented code.
Currently I have a piece of code that populates a list with objects and its properties that goes like this:
foreach (var folder in pathList)
{
DirectoryInfo di = new DirectoryInfo(folder);
foreach (var file in di.GetFiles())
{
fileinfoList.Add(new FileInfo()
{
partNumber = Path.GetFileNameWithoutExtension(Convert.ToString(file)),
fileType = Path.GetExtension(Convert.ToString(file)),
lastDate = file.LastWriteTime,
released = 1,
checkedBy = null,
fullPath = Path.GetFullPath(Convert.ToString(folder)),
});
}
}
What I need is to add the baseID property to each of the objects. This is what I have currently:
foreach (var item in fileNameList)
{
if (fileinfoList.Select(m => m.partNumber == dummyString.ToString()) != null)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = #"data source = MYPC\SQLEXPRESS; database = MYDB; integrated security = TRUE";
string query = $#"SELECT id FROM MYTABLE WHERE fullpath= '{pathsToFilesNotOnDbList[y]}' ";
var cmd = new SqlCommand(query, conn);
conn.Open();
SqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
iD = Convert.ToInt16(dataReader["id"]);
fileinfoList.Select (f => f.baseID = iD) ;
Console.WriteLine(y);
y++;
}
conn.Close();
}
}
I want this loop to take the value of iD and assign it to the baseID property.
I can get the iD's just fine, however I'm aware that the lambda expression fileinfoList.Select (f => f.baseID = iD) does nothing currently.
Can someone help me out?
If you want to set baseId = iD to all the elements of the list fileinfoList, just use:
fileinfoList.ForEach(i => i.baseID = iD);
UPDATE: set different id to each element:
var index = 0;
while (dataReader.Read())
{
iD = Convert.ToInt16(dataReader["id"]);
fileinfoList[index].baseID = id;
Console.WriteLine(y);
y++;
index++;
}
One way or another you need to know which object in fileinfoList you want to update with each id value.
Assuming fullpath field is unique across the dataset and an identifier for the object in fileinfoList as well as MYTABLE you can make the following updates and it should work for you:
Update Query to include fullpath field in returned data:
string query = $#"SELECT id, fullpath FROM MYTABLE WHERE fullpath= '{pathsToFilesNotOnDbList[y]}' ";
Update assignment statement to filter fileinfoList by fullpath before attempting to assign the value from the db:
fileinfoList.FirstOrDefault(f => f.fullpath == dataReader["fullPath"]).baseID = iD;
Full code:
foreach (var item in fileNameList)
{
if (fileinfoList.Select(m => m.partNumber == dummyString.ToString()) != null)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = #"data source = MYPC\SQLEXPRESS; database = MYDB; integrated security = TRUE";
string query = $#"SELECT id, fullpath FROM MYTABLE WHERE fullpath= '{pathsToFilesNotOnDbList[y]}' ";
var cmd = new SqlCommand(query, conn);
conn.Open();
SqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
iD = Convert.ToInt16(dataReader["id"]);
fileinfoList.FirstOrDefault(f => f.fullpath == dataReader["fullPath"]).baseID = iD;
Console.WriteLine(y);
y++;
}
conn.Close();
}
}
I keep getting this error when I try to find by ID:
system.data.oledb.oledbexception the speciefied field 'ID' could refer
to more than one table listed in the FROM clause of your SQL Statement
Here's my code:
public static Invoice GetInvoice(string id)
{
OleDbConnection conn = GetConnection();
Invoice invoice = null;
if (conn == null)
{
return null;
}
string sqlString = "SELECT * FROM Person INNER JOIN Employee ON " +
"Person.ID=Employee.ID WHERE ID = #ID";
OleDbCommand comm = new OleDbCommand(sqlString, conn);
comm.Parameters.AddWithValue("#ID", id);
OleDbDataReader dr = null;
try
{
conn.Open();
dr = comm.ExecuteReader(CommandBehavior.SingleRow);
if (dr.Read())
{
invoice = new Invoice();
invoice.PersonID = (string)dr["ID"];
invoice.FirstName = (string)dr["FirstName"];
invoice.LastName = (string)dr["LastName"];
invoice.Age = (int)dr["Age"];
}
}
catch (Exception ex)
{
invoice = null;
MessageBox.Show(ex.ToString());
}
finally
{
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
return invoice;
}
You need to change your query, at the moment you're selecting a wildcard '*', which means it will pull both the Persons ID and the Employee ID, but wont have a unique reference. Change your wildcard to pull the exact tables ID like below:
SELECT Person.ID, FirstName, LastName FROM...
You will also need to change your WHERE statement to something like:
WHERE Person.ID = #ID
as the where statement doesnt know which tables ID to filter on (i know they're the same values, but SQL doesnt care about that)
I am using FluentMigrator to migrate one database schema to another. I have a case in which I want to check if a foreign key exists before deleting it.
Previously, I just delete the foreign key by doing:
Delete.ForeignKey("FK_TableName_FieldName").OnTable("TableName");
How do I check that the foreign key exists first?
This is how to delete a foreign key if it exists using FluentMigrator:
if (Schema.Table("TableName").Constraint("FK_TableName_FieldName").Exists())
{
Delete.ForeignKey("FK_TableName_FieldName").OnTable("TableName");
}
Based on this https://stackoverflow.com/a/17501870/10460456 you can use Execute.WithConnection function to test if foreign key exist before delete it.
Execute.WithConnection((connection, transaction) =>
{
DeleteForeignKeyIfExist(connection, transaction, "yourReferencedTable", "yourTable", "foreignColumnName", "foreignKeyName");
});
public bool DeleteForeignKeyIfExist(IDbConnection connection, IDbTransaction transaction, string referenceTable, string table, string foreignKeyColumn, string foreignKeyConstrainName)
{
using (var cmd = transaction.Connection.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandType = CommandType.Text;
cmd.CommandText = ForeignKeyExistCommand(referenceTable, foreignKeyColumn);
bool foreignKeyExist = false;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// If this code is reached, the foreign key exist
foreignKeyExist = true;
break;
}
}
if (foreignKeyExist)
{
cmd.CommandText = $"ALTER TABLE [{table}] DROP CONSTRAINT [{foreignKeyConstrainName}];";
cmd.ExecuteNonQuery();
return true;
}
}
return false;
}
private string ForeignKeyExistCommand(string foreignTable, string innerColumn)
{
return $"SELECT OBJECT_NAME(f.parent_object_id) TableName, " +
"COL_NAME(fc.parent_object_id, fc.parent_column_id) ColName " +
"FROM sys.foreign_keys AS f INNER JOIN sys.foreign_key_columns AS fc " +
"ON f.OBJECT_ID = fc.constraint_object_id INNER JOIN sys.tables t " +
$"ON t.OBJECT_ID = fc.referenced_object_id WHERE OBJECT_NAME(f.referenced_object_id) = '{foreignTable}' " +
$"and COL_NAME(fc.parent_object_id,fc.parent_column_id) = '{innerColumn}'";
}