Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将数据表的所有行(包括Id值)插入SQL Server表_C#_.net_Sql Server_Ado.net_Sql Server Ce - Fatal编程技术网

C# 将数据表的所有行(包括Id值)插入SQL Server表

C# 将数据表的所有行(包括Id值)插入SQL Server表,c#,.net,sql-server,ado.net,sql-server-ce,C#,.net,Sql Server,Ado.net,Sql Server Ce,我试图使用ADO.NET将数据表的内容逐字插入SQL Server数据库。(注意:我目前使用的是SQL Server CE,但我希望有一个在常规或CE中都能工作的解决方案。) 使用以下代码生成的命令不包括Id列: var builder = new SqlCeCommandBuilder(); builder.DataAdapter = adapter; builder.SetAllValues = true; var command = builder.GetInsertCommand(tru

我试图使用ADO.NET将
数据表的内容逐字插入SQL Server数据库。(注意:我目前使用的是SQL Server CE,但我希望有一个在常规或CE中都能工作的解决方案。)

使用以下代码生成的命令不包括
Id
列:

var builder = new SqlCeCommandBuilder();
builder.DataAdapter = adapter;
builder.SetAllValues = true;
var command = builder.GetInsertCommand(true);
这会导致自动生成
Id
,这不是我想要的。我需要将每个
Id
复制到与
DataTable
中显示的完全相同的位置

使用
GetInsertCommand()
时,有没有办法强制
SqlCeCommandBuilder
在insert命令中包含
Id
字段?如果没有,还有其他解决办法吗?我愿意使用ADO.NET或EntityFramework

请注意,Id列是具有
AutoIncrement=true
的主键

编辑

我想出了一个我认为是解决这个问题的办法,但结果只是制造了另一个问题(见下面我的答案)。所以,我仍然在寻找一个很好的答案

编辑2


我刚刚编辑了我的答案。我想我找到了解决办法。仍然笨重且特定于数据库。希望使用合适的ADO.NET或EntityFramework解决方案。

在更改表架构(AutoIncrement=false)之前,您将无法插入Id,尽管您将手动准备insert语句。

我花了大量时间处理
CommandBuilder
,包括手动插入“Id”输入CommandText并向参数添加Id,但我就是无法让它工作

因此,我决定暂时放弃,自己滚动插入查询。下面的代码似乎适用于我抛出的几个示例场景,但在
ItemToSqlFormattedValue()
中可能缺少一些转换

非常感谢您的评论/更正,如果您有更好的解决方案,请将其作为答案发布

public virtual void FillDatabaseTable(DataTable table)
{
    var connection = _dbContextLocator.Current.Database.Connection;
    connection.Open();
    SetIdentityInsert(table, connection, true);
    FillDatabaseRecords(table, connection);
    SetIdentityInsert(table, connection, false);
    connection.Close();
}

private void FillDatabaseRecords(DataTable table, DbConnection connection)
{
    var command = GetNewCommand();
    command.Connection = connection;
    var rawCommandText = string.Format("insert into {0} values ({1})", table.TableName, "{0}");
    foreach (var row in table.AsEnumerable())
        FillDatabaseRecord(row, command, rawCommandText);
}

private void FillDatabaseRecord(DataRow row, DbCommand command, string rawCommandText)
{
    var values = row.ItemArray.Select(i => ItemToSqlFormattedValue(i));
    var valueList = string.Join(", ", values);
    command.CommandText = string.Format(rawCommandText, valueList);
    command.ExecuteNonQuery();
}

private string ItemToSqlFormattedValue(object item)
{
    if (item is System.DBNull)
        return "NULL";
    else if (item is bool)
        return (bool)item ? "1" : "0";
    else if (item is string)
        return string.Format("'{0}'", ((string)item).Replace("'", "''"));
    else if (item is DateTime)
        return string.Format("'{0}'", ((DateTime)item).ToString("yyyy-MM-dd HH:mm:ss"));
    else
        return item.ToString();
}

private void SetIdentityInsert(DataTable table, DbConnection connection, bool enable)
{
    var command = GetNewCommand();
    command.Connection = connection;
    command.CommandText = string.Format(
        "set IDENTITY_INSERT {0} {1}",
        table.TableName,
        enable ? "on" : "off");
    command.ExecuteNonQuery();
}

编辑

我发现这个有问题。尽管禁用了IDENTITY_INSERT,但SQL Server CE似乎无法确定下一个ID应该是什么,因此如果您尝试在未指定ID值的情况下进行插入,它将失败,并出现以下错误:

无法将重复值插入到唯一索引中

我猜SQLServerCE在计算下一个Id应该是什么时,不仅仅使用
MAX(Id)+1
。我相信它会根据过去的插入来跟踪它,但是当在打开IDENTITY_INSERT的情况下执行插入时,这种跟踪不会发生。这是我的直觉

因此,目前,如果数据库是只读的,或者您总是生成自己的Id,那么这实际上是唯一可行的解决方案


编辑2

我认为/希望这能解决问题:

public virtual void FillDatabaseTable(DataTable table)
{
    var connection = _dbContextLocator.Current.Database.Connection;
    connection.Open();
    ReseedIdColumn(table, connection);
    SetIdentityInsert(table, connection, true);
    FillDatabaseRecords(table, connection);
    SetIdentityInsert(table, connection, false);
    connection.Close();
}

private void ReseedIdColumn(DataTable table, DbConnection connection)
{
    if (table.Rows.Count == 0) return;
    var command = GetNewCommand();
    command.Connection = connection;
    command.CommandText = string.Format(
        "alter table {0} alter column Id IDENTITY ({1}, 1)",
        table.TableName,
        table.AsEnumerable().Max(t => t.Field<int>("Id")) + 1);
    command.ExecuteNonQuery();
}

// note: for SQL Server, may need to replace `alter table` statement with this:
// "dbcc checkident({0}.Id, reseed, {1})"

private void FillDatabaseRecords(DataTable table, DbConnection connection)
{
    var command = GetNewCommand();
    command.Connection = connection; //todo combine this sequence
    var rawCommandText = string.Format("insert into {0} values ({1})", table.TableName, "{0}");
    foreach (var row in table.AsEnumerable())
        FillDatabaseRecord(row, command, rawCommandText);
}

private void FillDatabaseRecord(DataRow row, DbCommand command, string rawCommandText)
{
    var values = row.ItemArray.Select(i => ItemToSqlFormattedValue(i));
    var valueList = string.Join(", ", values);
    command.CommandText = string.Format(rawCommandText, valueList);
    command.ExecuteNonQuery();
}

private string ItemToSqlFormattedValue(object item)
{
    const string quotedItem = "'{0}'";
    if (item is System.DBNull)
        return "NULL";
    else if (item is bool)
        return (bool)item ? "1" : "0";
    else if (item is Guid)
        return string.Format(quotedItem, item.ToString());
    else if (item is string)
        return string.Format(quotedItem, ((string)item).Replace("'", "''"));
    else if (item is DateTime)
        return string.Format(quotedItem, ((DateTime)item).ToString("yyyy-MM-dd HH:mm:ss"));
    else
        return item.ToString();
}

private void SetIdentityInsert(DataTable table, DbConnection connection, bool enable)
{
    var command = GetNewCommand();
    command.Connection = connection;
    command.CommandText = string.Format(
        "set IDENTITY_INSERT {0} {1}",
        table.TableName,
        enable ? "on" : "off");
    command.ExecuteNonQuery();
}
公共虚拟空填充DatabaseTable(DataTable)
{
var connection=_dbContextLocator.Current.Database.connection;
connection.Open();
ReseedColumn(表、连接);
SetIdentityInsert(表,连接,真);
填充数据库记录(表、连接);
SetIdentityInsert(表,连接,false);
connection.Close();
}
专用void ResedColumn(数据表、数据库连接)
{
if(table.Rows.Count==0)返回;
var命令=GetNewCommand();
command.Connection=连接;
command.CommandText=string.Format(
“alter table{0}alter column Id IDENTITY({1},1)”,
table.TableName,
表.AsEnumerable().Max(t=>t.Field(“Id”)+1);
command.ExecuteNonQuery();
}
//注意:对于SQL Server,可能需要将'alter table'语句替换为以下语句:
//dbcc checkident({0}.Id,重新设定种子,{1})
私有void FillDatabaseRecords(DataTable表、DbConnection连接)
{
var命令=GetNewCommand();
command.Connection=Connection;//todo组合此序列
var rawCommandText=string.Format(“插入到{0}值({1})”,table.TableName,“{0}”);
foreach(表中的var行。AsEnumerable())
FillDatabaseRecord(行、命令、rawCommandText);
}
私有void FillDatabaseRecord(DataRow行、DbCommand命令、字符串rawCommandText)
{
var values=row.ItemArray.Select(i=>ItemToSqlFormattedValue(i));
var valueList=string.Join(“,”值);
command.CommandText=string.Format(rawCommandText,valueList);
command.ExecuteNonQuery();
}
私有字符串ItemToSqlFormattedValue(对象项)
{
常量字符串quotedItem=“{0}”;
if(项为System.DBNull)
返回“NULL”;
否则,如果(项目为布尔)
退货(bool)项目?“1”:“0”;
else if(项为Guid)
返回string.Format(quotedItem,item.ToString());
else if(项为字符串)
返回string.Format(quotedItem,((string)项)。替换(“,”);
else if(项目为日期时间)
返回string.Format(quotedItem,((DateTime)项).ToString(“yyyy-MM-dd-HH:MM:ss”);
其他的
return item.ToString();
}
私有void SetIdentityInsert(数据表、数据库连接、布尔启用)
{
var命令=GetNewCommand();
command.Connection=连接;
command.CommandText=string.Format(
“设置标识\u插入{0}{1}”,
table.TableName,
启用“开”:“关”);
command.ExecuteNonQuery();
}

关键的区别是,我现在正在为Id列重新设置种子。这似乎奏效了。

嗨,伊布拉姆,我在理解上有点困难。你是说我需要手动编写insert语句并设置
AutoIncrement=false
?对不起,我的法语不好:)我的意思是这是不可能的,因为AutoIncrement=true。只有当您更改为AutoIncrement=false时,它才会工作。@ibtram,我确实尝试过,但是insert命令中仍然缺少
Id