数据库操作预计会影响 1 行但实际上影响了 0 行 entity framework
Database operation expected to affect 1 row(s) but actually affected 0 row(s) with entity framework
我有以下 table:
我有以下触发器:
CREATE TRIGGER check_insertion_to_pushes_table
BEFORE INSERT
ON "Pushes"
FOR EACH ROW
EXECUTE PROCEDURE trg_insert_failed_push();
CREATE or replace FUNCTION trg_insert_failed_push()
RETURNS trigger AS
$func$
BEGIN
IF (NEW."Sent" = false) THEN
IF EXISTS(
SELECT *
FROM "Pushes"
where "Sent" = false
and "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId"
)
THEN
RETURN NULL;
END IF;
RETURN NEW;
ELSE
RETURN NEW;
end if;
END
$func$ LANGUAGE plpgsql;
如果数据库中有行 CustomerId
和 PushTemplateId
和 Sent
等于新行并且 Sent
为 false 我想通过插入。
我有以下测试来检查它是如何工作的:
public class Tests
{
private IPushRepository _pushRepository;
[NUnit.Framework.SetUp]
public void Setup()
{
var confBuilder = new ConfigurationBuilder();
var configuration = confBuilder.AddJsonFile("/home/aleksej/projects/makeapppushernet/TestProject/appsettings.LocalToProdDb.json").Build();
_pushRepository = new PushRepository(new ApplicationDbContext(configuration));
}
[Test]
public async Task Test1()
{
var push = new Push
{
CustomerId = 69164,
Sent = false,
PackageId = "com.kek.lol",
Category = "betting",
Advertiser = "Advertiser",
TemplateType = "opened_and_not_registration",
IntervalType = "minutes",
BottomDateTimeBorder = 90,
TopDateTimeBorder = 60,
ClientStartDateTime = DateTime.Now,
FCMResponse = "hello",
CreatedAt = DateTime.Now,
LangCode = "En",
PushBody = "Hello",
PushTitle = "Hello",
PushTemplateId = 15
};
var pushesList = new List<Push>
{
push
};
await _pushRepository.SaveAsync(pushesList);
Assert.Pass();
}
}
如果我在测试中为 Sent
设置 false
,我会出现以下异常:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
如果我设置true
我什么都没有。它只是通过插入。
更新
好的,在 Shay Rojansky 的回答的帮助下,我有以下触发代码:
CREATE TRIGGER check_insertion_to_failed_pushes_table
BEFORE INSERT
ON "FailedPushes"
FOR EACH ROW
EXECUTE PROCEDURE trg_insert_failed_push();
CREATE or replace FUNCTION trg_insert_failed_push()
RETURNS trigger AS
$func$
DECLARE
push "FailedPushes"%ROWTYPE;
old_push_id numeric;
BEGIN
old_push_id = (SELECT "FailedPushId"
FROM "FailedPushes"
where "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId");
push := new;
IF (old_push_id != 0)
THEN
push."FailedPushId" = old_push_id;
DELETE
FROM "FailedPushes"
where "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId";
return push;
END IF;
push."FailedPushId" = (SELECT count(*) FROM "FailedPushes")::numeric + 1;
return push;
END
$func$ LANGUAGE plpgsql;
也许不是很优雅,但它确实有效。
您实际上是在将 PostgreSQL 配置为在某些情况下忽略 INSERT,但 EF Core 不会以任何方式意识到这一点。当您告诉 EF Core 添加新行时,它会期望在数据库中实际发生这种情况。如果实体有任何数据库生成的列(标识、序列),EF Core 还希望接收新插入行的值(并将它们填充回实体的 CLR 实例)。
所以据我所知,您不能只告诉数据库忽略 INSERT 并期望一切正常...
请参阅 this issue 关于 EF Core upsert 支持,这有点相关。
也许您的模型在控制器中解析为 Action 可能没有准确的值。
我有以下 table:
我有以下触发器:
CREATE TRIGGER check_insertion_to_pushes_table
BEFORE INSERT
ON "Pushes"
FOR EACH ROW
EXECUTE PROCEDURE trg_insert_failed_push();
CREATE or replace FUNCTION trg_insert_failed_push()
RETURNS trigger AS
$func$
BEGIN
IF (NEW."Sent" = false) THEN
IF EXISTS(
SELECT *
FROM "Pushes"
where "Sent" = false
and "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId"
)
THEN
RETURN NULL;
END IF;
RETURN NEW;
ELSE
RETURN NEW;
end if;
END
$func$ LANGUAGE plpgsql;
如果数据库中有行 CustomerId
和 PushTemplateId
和 Sent
等于新行并且 Sent
为 false 我想通过插入。
我有以下测试来检查它是如何工作的:
public class Tests
{
private IPushRepository _pushRepository;
[NUnit.Framework.SetUp]
public void Setup()
{
var confBuilder = new ConfigurationBuilder();
var configuration = confBuilder.AddJsonFile("/home/aleksej/projects/makeapppushernet/TestProject/appsettings.LocalToProdDb.json").Build();
_pushRepository = new PushRepository(new ApplicationDbContext(configuration));
}
[Test]
public async Task Test1()
{
var push = new Push
{
CustomerId = 69164,
Sent = false,
PackageId = "com.kek.lol",
Category = "betting",
Advertiser = "Advertiser",
TemplateType = "opened_and_not_registration",
IntervalType = "minutes",
BottomDateTimeBorder = 90,
TopDateTimeBorder = 60,
ClientStartDateTime = DateTime.Now,
FCMResponse = "hello",
CreatedAt = DateTime.Now,
LangCode = "En",
PushBody = "Hello",
PushTitle = "Hello",
PushTemplateId = 15
};
var pushesList = new List<Push>
{
push
};
await _pushRepository.SaveAsync(pushesList);
Assert.Pass();
}
}
如果我在测试中为 Sent
设置 false
,我会出现以下异常:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
如果我设置true
我什么都没有。它只是通过插入。
更新
好的,在 Shay Rojansky 的回答的帮助下,我有以下触发代码:
CREATE TRIGGER check_insertion_to_failed_pushes_table
BEFORE INSERT
ON "FailedPushes"
FOR EACH ROW
EXECUTE PROCEDURE trg_insert_failed_push();
CREATE or replace FUNCTION trg_insert_failed_push()
RETURNS trigger AS
$func$
DECLARE
push "FailedPushes"%ROWTYPE;
old_push_id numeric;
BEGIN
old_push_id = (SELECT "FailedPushId"
FROM "FailedPushes"
where "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId");
push := new;
IF (old_push_id != 0)
THEN
push."FailedPushId" = old_push_id;
DELETE
FROM "FailedPushes"
where "CustomerId" = NEW."CustomerId"
and "PushTemplateId" = NEW."PushTemplateId";
return push;
END IF;
push."FailedPushId" = (SELECT count(*) FROM "FailedPushes")::numeric + 1;
return push;
END
$func$ LANGUAGE plpgsql;
也许不是很优雅,但它确实有效。
您实际上是在将 PostgreSQL 配置为在某些情况下忽略 INSERT,但 EF Core 不会以任何方式意识到这一点。当您告诉 EF Core 添加新行时,它会期望在数据库中实际发生这种情况。如果实体有任何数据库生成的列(标识、序列),EF Core 还希望接收新插入行的值(并将它们填充回实体的 CLR 实例)。
所以据我所知,您不能只告诉数据库忽略 INSERT 并期望一切正常...
请参阅 this issue 关于 EF Core upsert 支持,这有点相关。
也许您的模型在控制器中解析为 Action 可能没有准确的值。