FluentMigrator - Check if Foreign Key exists before deleting it - c#

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}'";
}

Related

how to write c# code if table not exists create a new table in db with same columns and insert the data

Developers, I am new to programming and c# coding I written a code to insert the Xml data into database and it is working perfect but my requirement in code is "if table is not exists create a new table with same columns in the DataBase and insert the data " so how can I write the code ?
public void SaveXmltoDB(List<MeterReading> MeterReadingList)
{
//OpenConnection();
// CreateTableIfNotExists();
foreach (var meterReading in MeterReadingList)
{
foreach(var interval in meterReading.IntervalDatalist)
{
foreach(var reading in interval.Readinglist)
{
string command = string.Format("insert into INTERVALDATA1(SerialNumber,TimeStamp,MeterData) VALUES ({0},'{1}',{2})", meterReading.MeterName, reading.TimeStamp.ToString(), reading.RawReading);
using (SqlConnection conn = new SqlConnection("server=LAPTOP-N6V52QKD\\AKHIL5656;" +
"Trusted_Connection=yes;" +
"database=ReportServer$AKHIL5656; " +
"connection timeout=30;" + "persist security info = True;" +
"Integrated Security = SSPI;"))
{
SqlCommand myCommand = new SqlCommand(command,conn);
myCommand.CommandType = System.Data.CommandType.Text;
conn.Open();
try
{
myCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
}
}
}
}
}
CloseConnection();
}
The above code is perfectly working to insert the data into my table ,In the above code how can I program If table not exists in the database create new table with same columns and insert the data?
can anyone help me on this?
Thanks,
I think this works for SQLServer and MYSQL:
Select * From Information_Schema.Tables Where Table_Name = 'TableName';
This returns all tables matching your name--1 row if the table exists, no rows if it doesn't.
I'm sure the fields returned can be reduced but since it's returning only one row I have never worried about it.
Here is summary of a code that I wrote yesterday with a few changes for the answer.
in the beginning the program checks if the table exist, using INFORMATION_SCHEMA.TABLES.
if the table is not exist it will be create with
createTableQuery field that represents the command for creating the new table. replace col1 col2 col 3... etc with your columns (SerialNumber,TimeStamp,MeterData... etc) replace the data types and use IDENTITY (1, 1) command if you need incremental value.
private void saveTableToDataBase()
{
string tableName = dbTableName;
// check if table exist in sql server db
if (IsTableExistInDb(tableName) == true) {
// table exist do something...
} else {
// create table, replace with your column names and data types
string createTableQuery = "CREATE TABLE " & "." & tableName & "(" & _
"ID int IDENTITY (1, 1) NOT NULL PRIMARY KEY, " & _
"Col1 int, " & _
"Col2 decimal(5,4), " & _
"Col3 int, " & _
"Col4 decimal(5,4), " & _
"Col5 int " & _
")"
// create table in database
Insert(createTableQuery);
}
}
public static Boolean IsTableExistInDb(string tableName)
{
Object result = ExecuteScalarWithAnonimusType("SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = " + "'" + tableName + "'", Con);
if (result != null && byte.Parse(result.ToString()) == 1)
{
return true;
}
else
{
return false;
}
}
public static object ExecuteScalarWithAnonimusType(string query)
{
Cmd = new SqlCommand(query, Con);
try
{
return Cmd.ExecuteScalar();
}
catch (Exception ex)
{
return null;
}
finally
{
if (Con.State != ConnectionState.Closed)
Con.Close(); Con.Close();
}
}
public static bool Insert(string command)
{
try {
con = new SqlConnection(System_Vars.SqlClientConnString);
con.Open();
cmd = new SqlCommand(command, con);
return cmd.ExecuteNonQuery();
} catch (Exception ex) {
return false;
} finally {
con.Close();
}
}
You don't want to try and do a create table from string SQL. I mean you could create stored procedure and then call it from code. But you probably want to do this during application setup program and not when the application runs.

How do INSERT INTO Firebird, with autoincrement for the primary key?

How do INSERT INTO Firebird, with autoincrement for the primary key?
For the table fields I have:
fstPriority VARCHAR(30), fstInfo VARCHAR(100), fstDateCreated VARCHAR(30), fstDateModified VARCHAR(30), fiKeyID INTEGER PRIMARY KEY
For the INSERT INTO I have:
FbConnection fbConn = new FbConnection(stOpenConn))
fbConn.Open();
...
FbTransaction fbTransaction = fbConn.BeginTransaction();
FbCommand fbCmd = new FbCommand("INSERT INTO " + stTableName + "(" + stFieldNames + ") VALUES ( #p0, #p1, #p2, #p3, #p4 ) RETURNING fiKeyID ", fbConn, fbTransaction);
but am uncertain what should be used for the
fbCmd.Parameters.AddWithValue
fbCmd.Parameters.AddWithValue("#p0", "1st value");
fbCmd.Parameters.AddWithValue("#p1", "2nd value");
fbCmd.Parameters.AddWithValue("#p2", "3rd value");
fbCmd.Parameters.AddWithValue("#p3", "4th value");
Then what? For fiKeyID, do I add
fbCmd.Parameters.AddWithValue("#p4", "");
Also, I see at http://www.firebirdfaq.org/faq29/ creating an autoincrement column, but am uncertain how to do this in C# ... Firebird ADO.NET ... FirebirdClient.5.8.0 ... Visual Studio 2013.
CREATE GENERATOR ...;
SET GENERATOR ...;
set term !! ;
CREATE TRIGGER ...
are not recognized by the Visual Studio compiler.
An important thing is that SET TERM is not part of the Firebird statement syntax, instead it is a client-side feature to set the statement terminator in query tools like ISQL. This terminator is necessary to know when a statement is complete and can be sent to the server. By default these tools do that on a semi-colon (;), but that doesn't work with PSQL (stored procedures, triggers), because PSQL code uses the semi-colon as well. To address this, these tools have SET TERM to switch this terminator.
Using the Firebird ADO.net provider however, you need to execute statements one at a time, so a statement terminator is irrelevant.
To be able to generate a primary key you can use the following solutions:
Firebird 3 has an identity type column, so you don't need to create a sequence and trigger yourself:
create table withgeneratedid(
id integer generated by default as identity primary key,
column2 varchar(100)
)
For Firebird 2.5 and earlier you will need to create a sequence and trigger:
create table withgeneratedid(
id integer primary key,
column2 varchar(100)
);
create sequence seq_withgeneratedid;
set term #;
create trigger withgeneratedid_bi before insert on withgeneratedid
as
begin
if (new.id is null) then new.id = next value for seq_withgeneratedid;
end#
set term ;#
When you insert values into a table and want to have a generated key, you should not include the id column in the column-list. Including the id column allows you to override the key value, but that might lead to future inserts generating a duplicate key!. If you do include the id column, then no key will be generated in the Firebird 3 example, in the Firebird 2.5 example a key will be generated if the value of the column is null, otherwise it will take the provided value.
In ADO.net you'd normally need to execute the statements individually (and not use set term). Alternatively, you could use FbScript to parse a DDL script and execute the parse statements. Note that FbScript does support (and even requires) set term.
To execute this with the Firebird ADO.net provider, you can do something like the example below. I have included three alternatives for creating the table Firebird3, Firebird2_5, and FbScriptFB2_5 (which is the same as Firebird2_5 but uses FbScript). It also show how to retrieve the generated key:
namespace FbGeneratedKeys
{
class Program
{
private static SolutionType solutionType = SolutionType.FbScriptFB2_5;
static void Main(string[] args)
{
var connectionString = new FbConnectionStringBuilder
{
Database = #"D:\temp\generatedkey.fdb",
ServerType = FbServerType.Default,
UserID = "SYSDBA",
Password = "masterkey",
}.ToString();
FbConnection.CreateDatabase(connectionString, pageSize: 8192, overwrite : true);
using (FbConnection connection = new FbConnection(connectionString))
using (FbCommand cmd = new FbCommand())
{
connection.Open();
cmd.Connection = connection;
switch (solutionType) {
case SolutionType.Firebird3:
Firebird3Example(cmd);
break;
case SolutionType.Firebird2_5:
Firebird2_5Example(cmd);
break;
case SolutionType.FbScriptFB2_5:
FbScriptFB2_5Example(cmd);
break;
}
cmd.CommandText = #"insert into withgeneratedid(column2) values (#column2) returning id";
cmd.Parameters.AddWithValue("#column2", "some value");
cmd.Parameters.Add(new FbParameter() { Direction = System.Data.ParameterDirection.Output });
cmd.ExecuteNonQuery();
Console.WriteLine("Id:" + cmd.Parameters[1].Value);
Console.ReadLine();
}
}
private static void Firebird3Example(FbCommand cmd)
{
// Firebird 3 identity column
cmd.CommandText = #"create table withgeneratedid(
id integer generated by default as identity primary key,
column2 varchar(100)
)";
cmd.ExecuteNonQuery();
}
private static void Firebird2_5Example(FbCommand cmd)
{
// Firebird 2.5 and earlier normal primary key with trigger to generate key
// Table
cmd.CommandText = #"create table withgeneratedid(
id integer primary key,
column2 varchar(100)
)";
cmd.ExecuteNonQuery();
// Sequence
cmd.CommandText = "create sequence seq_withgeneratedid";
cmd.ExecuteNonQuery();
// Trigger
cmd.CommandText = #"create trigger withgeneratedid_bi before insert on withgeneratedid
as
begin
if (new.id is null) then new.id = next value for seq_withgeneratedid;
end";
cmd.ExecuteNonQuery();
}
private static void FbScriptFB2_5Example(FbCommand cmd)
{
string script = #"
create table withgeneratedid(
id integer primary key,
column2 varchar(100)
);
create sequence seq_withgeneratedid;
set term #;
create trigger withgeneratedid_bi before insert on withgeneratedid
as
begin
if (new.id is null) then new.id = next value for seq_withgeneratedid;
end#
set term ;#
";
FbScript fbScript = new FbScript(script);
fbScript.Parse();
FbBatchExecution exec = new FbBatchExecution(cmd.Connection);
exec.AppendSqlStatements(fbScript);
exec.Execute();
}
}
enum SolutionType
{
Firebird3,
Firebird2_5,
FbScriptFB2_5
}
}
Definitions:
public const string stMAIN_TABLE_NAME = " OrgTable ";
public const string stDELETED_TABLE_NAME = " BackupTable ";
public const string stFIELD_DEFINITIONS = " fstPriority VARCHAR(30)" +
", fstInfo VARCHAR(100)" +
", fstDateCreated VARCHAR(30)" +
", fstDateModified VARCHAR(30)" +
", fiKeyID INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ";
public const string stFIELD_NAMES = " fstPriority" +
", fstInfo" +
", fstDateCreated" +
", fstDateModified" +
", fiKeyID ";
public const string stFIELD_NAMES_NO_KEY_ID = " fstPriority" +
", fstInfo" +
", fstDateCreated" +
", fstDateModified ";
Code:
//------------------------------
static private bool boCreateDatabaseTables(string stPathFilename,
string stUserID,
string stPassword,
List<string> liststTableNames,
List<string> liststFieldDefinitions)
{
bool boErrorFlag = false;
int iTablesCount = liststTableNames.Count();
string stOpenConn = new FbConnectionStringBuilder {
Database = stPathFilename,
UserID = stUserID,
Password = stPassword,
ServerType = FbServerType.Embedded,
ClientLibrary = stCLIENT_LIBRARY
}.ToString();
using (FbConnection fbConn = new FbConnection(stOpenConn)) {
try {
fbConn.Open();
FbTransaction fbTransaction = fbConn.BeginTransaction();
for (int ii = 0; ii < iTablesCount; ii++) {
string stSql = "CREATE TABLE " + liststTableNames[ii] + "( " + liststFieldDefinitions[ii] + ")";
FbCommand fbCmd = new FbCommand(stSql, fbConn, fbTransaction);
fbCmd.ExecuteNonQuery();
}
fbTransaction.Commit();
}
catch (Exception ex) {
boErrorFlag = true;
MessageBox.Show("catch ... GlobalsFirebird ... boCreateDatabaseTables ... " + ex.Message);
}
}
return boErrorFlag;
}//boCreateDatabaseTables
//------------------------------
//------------------------------
static public bool boAddRow(string stPathFilename,
string stUserID,
string stPassword,
string stTableName,
string stFieldNamesNoKeyId,
List<string> liststFieldValuesNoKeyId)
{
bool boErrorFlag = false;
string stOpenConn = new FbConnectionStringBuilder {
Database = stPathFilename,
UserID = stUserID,
Password = stPassword,
ServerType = FbServerType.Embedded,
ClientLibrary = stCLIENT_LIBRARY
}.ToString();
using(FbConnection fbConn = new FbConnection(stOpenConn)) {
fbConn.Open();
try {
string stValuesPlaceHolder = "#p0";
for (int iii = 1; iii < liststFieldValuesNoKeyId.Count; iii++)
stValuesPlaceHolder += ", #p" + (iii).ToString();
FbTransaction fbTransaction = fbConn.BeginTransaction();
string stCmd = "INSERT INTO " + stTableName + "(" + stFieldNamesNoKeyId + ") VALUES ( " + stValuesPlaceHolder + " ) RETURNING fiKeyID ";
FbCommand fbCmd = new FbCommand(stCmd, fbConn, fbTransaction);
for (int iii = 0; iii < liststFieldValuesNoKeyId.Count; iii++) {
string stPlaceHolder = "#p" + (iii).ToString();
string stValue = liststFieldValuesNoKeyId[iii];
fbCmd.Parameters.AddWithValue(stPlaceHolder, stValue);
}
fbCmd.Parameters.Add(new FbParameter() { Direction = System.Data.ParameterDirection.Output });
fbCmd.ExecuteNonQuery();
fbTransaction.Commit();
}
catch (Exception ex) {
boErrorFlag = true;
MessageBox.Show("catch ... GlobalsFirebird ... boAddRow ... " + ex.Message);
}
}
return boErrorFlag;
}//boAddRow
//------------------------------

c# - Generate xml with table constraints as tags and column names as value

I need to generate an XML like the below one with constraints as tags and column name as values for a specific DB table in c#.
<tablename>
<key>ProductId</key>
<composite>
<column>ProductId</column>
<column>ProductCode</column>
<composite>
<ForeignKey>
<column>ProductBaseId</column>
</ForeignKey>
</tablename>
Can anyone help on this?
Here you will find the primary key:
SELECT Col.Column_Name from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND Constraint_Type = 'PRIMARY KEY'
AND Col.Table_Name = 'tablename'
If you have multiple PRIMARY KEYS, then you will get them from the same query above. You can just count the primary key and if they are more than 1 then you can list them in Composite. Otherwise just put them as Key.
Here is another point, If there are two primary keys, then what will be in <KEY> tag?
Here you will find Foreign Keys:
SELECT Col.Column_Name from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND Constraint_Type = 'FOREIGN KEY'
AND Col.Table_Name = 'tablename'
Just join two information and write in XML. XML writing is so easy, here you can find it. XML Writing - DotNetPerls
UPDATE 1 :
Here is a code, where you can find the pK and FK both and with type from single query.
SELECT Col.Column_Name,
Case When( CHARINDEX('PK_' , Col.CONSTRAINT_NAME) >0 ) Then 'PK' ELSE 'FK' END as Type
from
INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND (Constraint_Type = 'PRIMARY KEY' OR Constraint_Type = 'Foreign KEY')
AND Col.Table_Name = 'table_1'
The Query output will like below:
Column_Name Type
AnotherID FK
Code PK
ID PK
I know it's not good that, I am providing codes fully. but as it was interesting to me, I have wrote some lines that may helpful to others also.
Here is the full code :
namespace XMLWritingFromDB
{
public class Program
{
public static string connectionstring = "Data Source=RAHIMPC\\SQLEXPRESS;Initial Catalog=Test;Integrated Security=false;uid=******;pwd=********";
public static SqlConnection conn;
static void Main(string[] args)
{
//Get the table Informations
DataTable dt = GetDataSchema("table_1"); // PUT YOUR TABLE NAME HERE.
string xmlDocument = PrepareXml(dt);
Console.Write(xmlDocument);
Console.ReadKey();
}
public static DataTable GetDataSchema(string TableName)
{
DataTable dt = new DataTable();
string query = "SELECT Col.Column_Name, Case When( CHARINDEX('PK_' , Col.CONSTRAINT_NAME) >0 ) Then 'PK' ELSE 'FK' END as Type " +
" from INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab, INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col " +
" WHERE Col.Constraint_Name = Tab.Constraint_Name AND Col.Table_Name = Tab.Table_Name " +
"AND (Constraint_Type = 'PRIMARY KEY' OR Constraint_Type = 'Foreign KEY') AND Col.Table_Name = '"+TableName+"'";
using (conn = new SqlConnection(connectionstring))
{
conn.Open();
using (SqlCommand sc = new SqlCommand(query, conn))
{
using (SqlDataReader dr = sc.ExecuteReader())
{
dt.Load(dr);
}
}
conn.Close();
}
return dt;
}
public static string PrepareXml(DataTable dt)
{
int pkCount = 0, fkCount = 0;
List<string> lstPK = new List<string>();
List<string> lstFK = new List<string>();
//Build data for xml
foreach (DataRow dr in dt.Rows)
{
if (dr[1].ToString().Contains("PK"))
{
pkCount++;
lstPK.Add(dr[0].ToString());
}
if (dr[1].ToString().Contains("FK"))
{
fkCount++;
lstFK.Add(dr[0].ToString());
}
}
List<TableName> lstXml = new List<TableName>();
TableName xml = new TableName();
xml.key = lstPK[lstPK.Count() - 1].ToString();
xml.ForeignKey = lstFK;
if (pkCount > 1)
xml.Composite = lstPK;
var stringwriter = new System.IO.StringWriter();
var serializer = new XmlSerializer(xml.GetType());
serializer.Serialize(stringwriter, xml);
return stringwriter.ToString();
}
}
[XmlRoot("TableName")]
public class TableName
{
public string key { get; set; }
[XmlArray(ElementName = "Composite")]
[XmlArrayItem("ColumnName", Type = typeof(string))]
public List<string> Composite { get; set; }
[XmlArray(ElementName = "ForeignKey")]
[XmlArrayItem("ColumnName", Type = typeof(string))]
public List<string> ForeignKey { get; set; }
}
}
You can use dataTableObject.WriteXml() method, this method contains various overloads.

How to truncate table when foreign dependencies exist via C#

For testing purposes I have a method that takes in a SqlConnection or a connection string and a string. The method examines the SqlConnection or the DbContext.Database.Connection.ConnectionString against a set of 'dangerous' strings, if the connection string has any 'dangerous' strings, it doesn't execute its query.
I basically need to know how to execute (via C#) a truncate/delete all data in table HOWEVER the problem is foreign dependencies. I am trying the following method. Remove all dependencies, delete the table and then reinstate all dependencies however I am having an issue with my reinstate all dependencies code. How can I do this via C#?
Main method that should delete the table.
public int DeleteFromDatabase(SqlConnection sqlConnection, string tableName)
{
int success = 0;
string sqlTrunc = "Delete from " + tableName;
if (isSafeSqlConnection(sqlConnection))
{
DropAllConstraints();
using (sqlConnection)
{
SqlCommand cmd = new SqlCommand(sqlTrunc, sqlConnection);
sqlConnection.Open();
success = cmd.ExecuteNonQuery();
sqlConnection.Close();
}
ReinstateAllConstraints(); //<=error happens here.
}
return success;
}
This drops all constraints:
public void DropAllConstraints()
{
string[] queries = File.ReadAllLines(#"Utility\UnsafeStrings\dropallcontraint.txt");
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
foreach (var item in queries)
{
var command = new SqlCommand(item, connection);
command.ExecuteNonQuery();
}
connection.Close();
}
}
This checks that the connection passed in isn't a live server:
private bool isSafeSqlConnection(SqlConnection connection)
{
string pathToUNsafeStrings = #"Utility\UnsafeStrings\UnsafeStrings.txt";
string[] unsafeStrings = File.ReadAllLines(pathToUNsafeStrings);
foreach (var item in unsafeStrings)
{
if (connection.ConnectionString.Contains(item))
return false;
}
return true;
}
This method essentially executes every entry returned from this query:
select
'ALTER TABLE dbo.' + object_name(fk.parent_object_id) +
' ADD CONSTRAINT ' + fk.name +
' FOREIGN KEY(' + c1.name + ') REFERENCES dbo.' +
object_name(fk.referenced_object_id) + '(' + c2.name + ')' as col1
from
sys.foreign_keys fk
inner join
sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
inner join
sys.columns c1 ON fkc.parent_column_id = c1.column_id and c1.object_id = fkc.parent_object_id
inner join
sys.columns c2 ON fkc.referenced_column_id = c2.column_id and c2.object_id = fkc.referenced_object_id
public void ReinstateAllConstraints()
{
string[] reinstateAllConstraints = File.ReadAllLines(#"Utility\UnsafeStrings\reisntateconstraint.txt");
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
foreach (var item in reinstateAllConstraints)
{
var command = new SqlCommand(item, connection);
command.ExecuteNonQuery();
}
connection.Close();
}
}
You can do this workflow:
Disable the foreign key check.
Delete all registers from tables that references the table that you want delete.
Delete all registers from table that you want delete.
Enable foreign key check.
You can see in this code below(I am using C# 6)
public bool TruncateTable(string tableName)
{
string sqlTrunc = $"Delete from {tableName}";
if (isSafeSqlConnection(sqlConnection))
{
DisableAllForeignKeys();
using (sqlConnection)
{
DeleteAllDependencies(tableName, sqlConnection);
SqlCommand cmd = new SqlCommand(sqlTrunc, sqlConnection);
sqlConnection.Open();
success = cmd.ExecuteNonQuery();
sqlConnection.Close();
}
EnableAllForeignKeys();
}
return success;
}
public void DisableAllForeignKeys(SqlConnection sqlConnection)
{
using(var command = new SqlCommand($"EXEC sp_msforeachtable \"ALTER TABLE ? NOCHECK CONSTRAINT all\"", sqlConnection))
command.ExecuteNonQuery();
}
public void EnableAllForeignKeys(SqlConnection sqlConnection)
{
using(var command = new SqlCommand($"EXEC sp_msforeachtable \"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all\"", sqlConnection))
command.ExecuteNonQuery();
}
private static void DeleteAllDependencies(string tableName, SqlConnection sqlConnection)
{
var sql =
$#"SELECT t.name AS 'Table that contains FK',
fk.name AS 'FK Name',
t1.Name AS 'Table that is being referenced'
FROM sys.foreign_key_columns fkc
INNER JOIN sys.tables t ON t.object_id = fkc.parent_object_id
INNER JOIN sys.tables t1 ON t1.object_id = fkc.referenced_object_id
INNER JOIN sys.columns c1 ON c1.object_id = fkc.parent_object_id AND c1.column_id = fkc.parent_column_id
INNER JOIN sys.foreign_keys fk ON fk.object_id = fkc.constraint_object_id
INNER JOIN sys.schemas sc ON t.schema_id = sc.schema_id
WHERE (sc.name + '.' +t1.name) = 'dbo.{
tableName}';";
var command = sqlConnection.CreateCommand();
command.CommandText = sql;
List<Tuple<string, string, string>> tuples;
using (var dataReader = command.ExecuteReader())
{
var enumerator = dataReader.GetEnumerator();
tuples = Enumerable.Range(1, int.MaxValue)
.TakeWhile(i => enumerator.MoveNext())
.Select(i => (IDataRecord)enumerator.Current)
.Select(dr => Tuple.Create(dr.GetString(0), dr.GetString(1), dr.GetString(2)))
.ToList();
}
foreach (var tuple in tuples)
{
using (var sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = $"DELETE FROM {tuple.Item1}";
sqlCommand.ExecuteNonQuery();
}
}
}
You might want to configure the relations to propagate changes accordingly ("cascade"), so that when one part of the relation is deleted, the other gets deleted or updated as well.
The DBMS is right in saying that you can not activate a fk relation if the items you are referring to from the other table are missing.

Upload image - ForeignKey conflict

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.

Categories