我正在尝试使用我的Laravel项目将SQL Server用于我的数据库。我能够将SQL Server与Laravel 5.2连接起来。但是,当我尝试将数据播种到表中时,我收到此错误
[Illuminate\Database\QueryException] SQLSTATE[23000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]Cann ot insert explicit value for identity column in table 'surveys' when IDENTITY_INSERT is set to OFF. (SQL: insert into [surveys] ([id], [name]) values (10, 'Some Text'))
注意:我正在尝试提供可能导致问题的身份值。
在研究SQL错误时,我了解到我需要执行以下查询。
播种前我需要执行
SET IDENTITY_INSERT surveys ON;
播种后我需要执行
SET IDENTITY_INSERT surveys OFF;
但我不知道如何使用Laravel
执行这些命令如何在没有此问题的情况下为标识列提供值时播种?
已更新 这是我的播种机
<?php
use Illuminate\Database\Seeder;
class FinalSurveyTS extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$myTable = 'surveys';
DB::statement('SET IDENTITY_INSERT ' . $myTable . ' ON');
DB::table($myTable)->truncate();
DB::table($myTable)->insert([
'id' => 10,
'name' => 'some name',
]);
DB::statement('SET IDENTITY_INSERT ' . $myTable . ' OFF');
}
}
答案 0 :(得分:3)
这是我找到的。
Laravel不支持交易中的原始声明。
任何原始语句都将单独执行,并与数据库建立单独的连接。
执行时的方法
#This script will update remote address rules with the specified IP scope(s)
$displayname = read-host "Enter firewall rule display name"
$rules = Get-NetFirewallRule -DisplayName $displayname | Where-Object {$_.Direction -eq "Inbound" -and ($_ | Get-NetFirewallAddressFilter).RemoteAddress -ne "LocalSubnet" }
$ips = @()
do {
$answer = (Read-Host "Please enter IP address")
if ($answer -ne '') {$ips += $answer}
}
until ($answer -eq '')
foreach ($rule in $rules)
{
#Set-NetFirewallRule -DisplayName $r.DisplayName -RemoteAddress $ips
write-host $rule.Displayname $ips
}
...
Laravel将处理3种不同的数据库连接。这意味着第二个语句永远不会知道第一个或第三个事务。在这种情况下,第一行不会影响到什么。
解决这个问题“直到Laravel添加对事务的原始语句的支持”是将insert语句创建为原始查询,如此
DB::statement('SET IDENTITY_INSERT surveys ON;');
DB::table(...)->insert(...);DB::table(...)->insert(...);DB::table(...)->insert(...);
DB::statement('SET IDENTITY_INSERT surveys ON;');
我希望这篇文章可以帮助别人。
答案 1 :(得分:2)
对于任何通过Google找到它的人-新的正确答案是像这样使用unprepared()
:
DB::beginTransaction();
DB::unprepared('SET IDENTITY_INSERT test ON');
DB::table('test')->insert(['id' => 1, 'name' => 'example']);
DB::unprepared('SET IDENTITY_INSERT test OFF');
DB::commit();
如在此问题线程上所讨论的:https://github.com/laravel/framework/issues/27778
答案 2 :(得分:1)
为了执行这些命令,您可以将其作为原始
执行DB::statement('SET IDENTITY_INSERT surveys ON;');
然后
DB::statement('SET IDENTITY_INSERT surveys OFF;');
DB :: statement适用于不返回数据的命令
修改强> 当播种机像这样执行时:
DB::statement(...);
DB::table(...)->insert(...);
DB::statement(...);
似乎由于某种原因未保留IDENTITY_INSERT变量的状态,因此使其工作的方法是将该代码包装在事务中。
try {
DB::beginTransaction();
DB::statement(...);
DB::table(...)->insert(...);
DB::statement(...);
DB::commit();
} catch(Exception $e) {
DB::rollback();
}
答案 3 :(得分:0)
任何原始语句都将通过与数据库的单独连接单独执行。
因此,您应该遵循我进行连接的方式; 这是示例代码;
DB::transaction(function () use ($reader, $dbDriver, $tableName) {
if ($dbDriver == 'pgsql') DB::statement('ALTER TABLE ' . $tableName . ' DISABLE TRIGGER ALL');
elseif ($dbDriver == 'sqlsrv')
{
$pdo = DB::connection()->getPdo();
$pdo->setAttribute(PDO::SQLSRV_ATTR_DIRECT_QUERY, true);
DB::statement('SET IDENTITY_INSERT ' . $tableName . ' ON');
}
foreach ($reader as $row) DB::table($tableName)->insert([$row]);
if ($dbDriver == 'pgsql') DB::statement('ALTER TABLE ' . $tableName . ' ENABLE TRIGGER ALL');
elseif ($dbDriver == 'sqlsrv')
{
DB::statement('SET IDENTITY_INSERT ' . $tableName . ' OFF');
$pdo->setAttribute(PDO::SQLSRV_ATTR_DIRECT_QUERY, false);
}
});
答案 4 :(得分:0)
我最终创建了以下方法来将IDENTITY_INSERT
控制为SQL表播种过程的ON / OFF:
function setIdentityInsert($table, $onStatus = true)
{
$status = $onStatus ? 'ON' : 'OFF';
$this->sqlConnection->unprepared("SET IDENTITY_INSERT $table $status");
}
function insertTableData($table, $data)
{
return $this->sqlConnection->table($table)->insert($data);
}
function seedTable($table, $hasAutoIncrementPrimaryKey = false, $data = [])
{
if ($hasAutoIncrementPrimaryKey) {
$this->setIdentityInsert($table);
$response = $this->insertTableData($table, $data);
$this->setIdentityInsert($table, false);
return $response;
}
else {
return $this->insertTableData($table, $data);
}
}
注意:通常,该表需要具有自动递增的主键才能将“身份插入”设置为ON
,这就是为什么要使用$hasAutoIncrementPrimaryKey
标志的原因。否则,播种可能会引发以下错误:
SQLSTATE[HY000]: General error: 544 Cannot insert explicit value for
identity column in table 'test_table_name' when IDENTITY_INSERT is set to
OFF. [544] (severity 16) [(null)]
希望这会有所帮助!