Ожидается, что работа с базой данных повлияет на 1 строку (и), но фактически затронула 0 строк (ы) с помощью структуры - PullRequest
0 голосов
/ 25 октября 2019

У меня есть следующая таблица:

enter image description here

И у меня есть следующий триггер:

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();
        }
    }

Если я установлю false для Sent в тесте, у меня будет следующее исключение:

Операция базы данных, как ожидается, затронет 1 строку (и), но фактически затронула 0 строк. Данные могут быть изменены или удалены, так как объекты были загружены. См. http://go.microsoft.com/fwlink/?LinkId=527962 для получения информации о понимании и обработке исключений оптимистичного параллелизма.

Если я установлю true, у меня ничего нет. Это просто проходит вставку.

Обновление

Хорошо, с помощью ответа Шэя Рожанского у меня есть следующий триггерный код:

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;

Возможно, не очень элегантно, но это работает.

1 Ответ

2 голосов
/ 25 октября 2019

Вы фактически настраиваете PostgreSQL на игнорирование INSERT при определенных условиях, но EF Core не знает об этом никоим образом. Когда вы говорите EF Core добавить новую строку, он ожидает, что это действительно произойдет в базе данных. Если у объекта есть какие-либо сгенерированные базой данных столбцы (идентификатор, последовательный), EF Core также ожидает получить их значения для вновь вставленной строки (и заполнит их обратно в экземпляр CLR объекта).

Таким образом, AFAIK, вы не можете просто сказать базе данных игнорировать INSERT и ожидать, что все будет работать ...

См. эту проблему о поддержке Esert Core Esertв некотором роде.

...