Bug in the insertion of several records with Entity Framework Core

-2

Good morning I'm trying to save a record that is of the "Event" type that can have 1 or more coupons, can also have 1 or more products, and can also have 1 or more additional fields. When I send the record containing only one item that I mentioned the code runs normally, however the problem occurs when I try to save more than one coupon, product or additional field at once. Error follows

System.Data.SqlClient.SqlException (0x80131904): Cannot resolve the collation conflict between "Latin1_General_CI_AI" and "Latin1_General_CS_AS" in the equal to operation. Cannot resolve the collation conflict between "Latin1_General_CI_AI" and "Latin1_General_CS_AS" in the equal to operation. Cannot resolve the collation conflict between "Latin1_General_CI_AI" and "Latin1_General_CS_AS" in the equal to operation. at System.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__126_0(Task 1 result) at System.Threading.Tasks.ContinuationResultTaskFromResultTask 2.InnerInvoke() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location where exception was thrown --- at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) --- End of stack trace from previous location where exception was thrown --- at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteAsync(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary 2 parameterValues, CancellationToken cancellationToken) ClientConnectionId:cf7d8065-3558-4dca-956e-5c6a2f9bd883 Error Number:468,State:9,Class:16

The tables involved are:

create database adventech_events_test collate Latin1_General_CI_AI;
go

use adventech_events_test;
go
-- Eventos
create table dbo.events(
    id char(8) collate Latin1_General_CS_AS not null default([dbo].[new_id]()),
    id_clustered int identity(1,1) not null,
    id_company char(8) collate Latin1_General_CS_AS not null,
    name varchar(100) not null,
    description nvarchar(4000),
    payment_type int not null,
    subscription_limit int not null,
    cash_value decimal(14,2) not null,
    installment_amount decimal(14,2) not null,
    installment_limit int not null,
    realization_date_begin datetimeoffset not null,
    realization_date_end datetimeoffset not null,
    registration_date_begin datetimeoffset not null,
    registration_date_end datetimeoffset not null,
    id_bank_account char(8) collate Latin1_General_CS_AS not null,
    is_active bit not null default 1,
    removed bit not null default 0,
    last_modified datetimeoffset,
    creation_date datetimeoffset not null default sysdatetimeoffset(),
    constraint UQ_events unique clustered (id_clustered),
    constraint PK_events primary key nonclustered (id),
    constraint FK_events_companies foreign key (id_company) references dbo.companies(id),
    constraint FK_events_payment_types foreign key (payment_type) references dbo.payment_types(id),
    constraint FK_events_bank_account foreign key (id_bank_account) references dbo.bank_accounts(id),
);
go

-- Produtos dos eventos
create table dbo.event_products(
    id char(8) collate Latin1_General_CS_AS not null default([dbo].[new_id]()),
    id_clustered int identity(1,1) not null,
    id_event char(8) collate Latin1_General_CS_AS not null,
    name varchar(100) not null,
    value decimal(14,2) not null,
    removed bit not null default 0,
    last_modified datetimeoffset,
    creation_date datetimeoffset not null default sysdatetimeoffset(),
    constraint UQ_event_products unique clustered (id_clustered),
    constraint PK_event_products primary key nonclustered (id),
    constraint FK_event_products_events foreign key (id_event) references dbo.events(id)
);
go


-- Cupons dos eventos
create table dbo.event_coupons(
    id char(8) collate Latin1_General_CS_AS not null default([dbo].[new_id]()),
    id_clustered int identity(1,1) not null,
    id_event char(8) collate Latin1_General_CS_AS not null,
    name varchar(100) not null,
    percentage char(3) not null,
    usage_limit int not null,
    quantity_used int not null default 0,
    removed bit not null default 0,
    last_modified datetimeoffset,
    creation_date datetimeoffset not null default sysdatetimeoffset(),
    constraint UQ_event_coupons unique clustered (id_clustered),
    constraint PK_event_coupons primary key nonclustered (id),
    constraint FK_event_coupons_events foreign key (id_event) references dbo.events(id)
);
go

-- Endereços dos eventos
create table dbo.event_addresses(
    id char(8) collate Latin1_General_CS_AS not null default([dbo].[new_id]()),
    id_clustered int identity(1,1) not null,
    id_event char(8) collate Latin1_General_CS_AS not null,
    cep varchar(8) not null,
    street varchar(100) not null,
    neighborhood varchar(100) not null,
    city varchar(100) not null,
    state varchar(2) not null,
    complement nvarchar(300),
    number int,
    removed bit not null default 0,
    last_modified datetimeoffset,
    creation_date datetimeoffset not null default sysdatetimeoffset(),
    constraint UQ_event_addresses unique clustered (id_clustered),
    constraint PK_event_addresses primary key nonclustered (id),
    constraint FK_event_addresses_events foreign key (id_event) references dbo.events(id)
);
go

-- Campos
create table dbo.fields(
    id char(8) collate Latin1_General_CS_AS not null default([dbo].[new_id]()),
    id_clustered int identity(1,1) not null,
    id_company char(8) collate Latin1_General_CS_AS not null,
    id_field_list char(8) collate Latin1_General_CS_AS,
    id_field_type int not null,
    name nvarchar(150),
    guiding_text nvarchar(4000),
    description nvarchar(4000),
    is_required bit not null default 0,
    is_active bit not null default 1,
    removed bit not null default 0,
    last_modified datetimeoffset,
    creation_date datetimeoffset not null default sysdatetimeoffset(),
    constraint UQ_fields unique clustered (id_clustered),
    constraint PK_fields primary key nonclustered (id),
    constraint FK_fields_companies foreign key (id_company) references dbo.companies(id),
    constraint FK_fields_field_types foreign key (id_field_type) references dbo.field_types(id),
    CONSTRAINT FK_fields_list FOREIGN KEY (id_field_list) REFERENCES field_lists(id),
);
go

-- Campos
create table dbo.event_fields(
    id char(8) collate Latin1_General_CS_AS not null default([dbo].[new_id]()),
    id_clustered int identity(1,1) not null,
    id_event char(8) collate Latin1_General_CS_AS not null,
    id_field char(8) collate Latin1_General_CS_AS,
    is_active bit not null default 1,
    removed bit not null default 0,
    last_modified datetimeoffset,
    creation_date datetimeoffset not null default sysdatetimeoffset(),
    constraint UQ_event_fields unique clustered (id_clustered),
    constraint PK_event_fields primary key nonclustered (id),
    constraint FK_event_fields_field foreign key (id_field) references dbo.fields(id),
    constraint FK_event_fields_event foreign key (id_event) references dbo.events(id),
);
go

My code is as follows:

public async Task<CommandResult> ExecuteAsync(EventsCommandsHandler handler)
        {
            this.Id = string.IsNullOrEmpty(this.Id) ? RandomId.NewId(8) : this.Id;
            var address = Address?.ToAddress(Id);
            if (address == null)
                return await Task.FromResult(new CommandResult(ErrorCode.InvalidParameters, "Parameter of address cannot be null"));

            var newEvent = new Event(
                id: this.Id,
                name: Name,
                description: Description,
                paymentType: PaymentType,
                subscriptionLimit: SubscriptionLimit,
                cashValue: CashValue,
                installmentAmount: InstallmentAmount,
                installmentLimit: InstallmentLimit,
                bankAccountId: BankAccountId,
                realizationDateBegin: RealizationDate.Begin,
                realizationDateEnd: RealizationDate.End,
                registrationDateBegin: RegistrationDate.Begin,
                registrationDateEnd: RegistrationDate.End,
                companyId: handler.CurrentRequest.CompanyId
            );

            await handler.DbContext.Events.AddAsync(newEvent);
            await handler.DbContext.EventAddresses.AddAsync(address);
            if (Products != null)
            {
                if (Products.Length > 0)
                {
                    var products = Products
                        .Select(p => p.ToProduct(newEvent.Id))
                        .Where(p => p != null)
                        .ToArray();
                    await handler.DbContext.Products.AddRangeAsync(products);
                }
            }

            if (Coupons != null)
            {
                if (Coupons.Length > 0)
                {
                    var coupons = Coupons
                        .Select(c => c.ToCoupon(newEvent.Id))
                        .Where(p => p != null)
                        .ToArray();
                    await handler.DbContext.Coupons.AddRangeAsync(coupons);
                }
            }

            if (EventFields != null)
            {
                if (EventFields.Length > 0)
                {
                    var eventFields = EventFields
                        .Select(c => c.ToEventField(newEvent.Id))
                        .Where(p => p != null)
                        .ToArray();
                    await handler.DbContext.EventFields.AddRangeAsync(eventFields);
                }
            }
            var rows = await handler.DbContext.SaveChangesAsync();

            return await Task.FromResult(new CommandResult(rows));
        }

This is an example of the function that I insert the components of the array:

public static Coupon ToCoupon(this CouponCommand command, string eventId)
        {
            if (string.IsNullOrWhiteSpace(command.Name) || string.IsNullOrWhiteSpace(command.Percentage) || command.UsageLimit < 0)
                return null;

            var coupon = new Coupon(
                id: String.IsNullOrWhiteSpace(command.Id) ? RandomId.NewId(8) : command.Id,
                name: command.Name,
                percentage: command.Percentage,
                usageLimit: command.UsageLimit,
                eventId: eventId
            );

            return coupon;
        }

And this is an example of the json I'm trying to save:

{
    "name": "teste Final",
    "description": "teste FInal",
    "subscriptionLimit": 100,
    "realizationDate": {
        "begin": "2020/03/25 4:28:04",
        "end": "2020/03/26 4:28:04"
    },
    "registrationDate": {
        "begin": "2020/02/27 4:28:01",
        "end": "2020/02/28 4:28:01"
    },
    "cashValue": 100,
    "installmentAmount": 120,
    "installmentLimit": 10,
    "bankAccountId": "weDDrewd",
    "paymentType": "2",
    "address": {
        "cep": "89221550",
        "street": "Rua Xanxerê",
        "neighborhood": "Saguaçu",
        "city": "Joinville",
        "state": "SC",
        "complement": "",
        "number": ""
    },
    "coupons": [{
        "name": "Cupom Criado",
        "percentage": "10",
        "usageLimit": 10
    }, {
        "name": "Cupom Criado",
        "percentage": "10",
        "usageLimit": 10
    }, {
        "name": "Cupom Criado",
        "percentage": "10",
        "usageLimit": 10
    }],
    "products": [{
        "name": "Cupom Criado",
        "value": 10
    }, {
        "name": "Cupom Criado",
        "value": 10
    }, {
        "name": "Cupom Criado",
        "value": 10
    }],
    "eventFields": [{
            "idField": "tpB90wbN"
        },
        {
            "idField": "E99RL71v"
        }, {
            "idField": "6YlfR7JO"
        },
        {
            "idField": "vbq5Uex0"
        }
    ]
}

This is an example of JSON that is saved if sent:

{
    "name": "teste Final",
    "description": "teste FInal",
    "subscriptionLimit": 100,
    "realizationDate": {
        "begin": "2020/03/25 4:28:04",
        "end": "2020/03/26 4:28:04"
    },
    "registrationDate": {
        "begin": "2020/02/27 4:28:01",
        "end": "2020/02/28 4:28:01"
    },
    "cashValue": 100,
    "installmentAmount": 120,
    "installmentLimit": 10,
    "bankAccountId": "weDDrewd",
    "paymentType": "2",
    "address": {
        "cep": "89221550",
        "street": "Rua Xanxerê",
        "neighborhood": "Saguaçu",
        "city": "Joinville",
        "state": "SC",
        "complement": "",
        "number": ""
    },
    "coupons": [{
        "name": "Cupom Criado",
        "percentage": "10",
        "usageLimit": 10
    }],
    "products": [{
        "name": "Cupom Criado",
        "value": 10
    }],
    "eventFields": [{
            "idField": "tpB90wbN"
        }
    ]
}

I believe the problem is in the temporary table that is created by the Entity Framework

SET NOCOUNT ON;
      INSERT INTO [dbo].[event_addresses] ([Id], [cep], [city], [complement], [id_event], [last_modified], [neighborhood], [number], [Removed], [state], [street])
      VALUES (@p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26);
      SELECT [creation_date]
      FROM [dbo].[event_addresses]
      WHERE @@ROWCOUNT = 1 AND [Id] = @p16;
  DECLARE @inserted1 TABLE ([Id] char(8), [_Position] [int]);
  MERGE [dbo].[event_coupons] USING (
  VALUES (@p27, @p28, @p29, @p30, @p31, @p32, @p33, @p34, 0),
  (@p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42, 1),
  (@p43, @p44, @p45, @p46, @p47, @p48, @p49, @p50, 2)) AS i ([Id], [id_event], [last_modified], [name], [percentage], [quantity_used], [Removed], [usage_limit], _Position) ON 1=0
  WHEN NOT MATCHED THEN
  INSERT ([Id], [id_event], [last_modified], [name], [percentage], [quantity_used], [Removed], [usage_limit])
  VALUES (i.[Id], i.[id_event], i.[last_modified], i.[name], i.[percentage], i.[quantity_used], i.[Removed], i.[usage_limit])
  OUTPUT INSERTED.[Id], i._Position
  INTO @inserted1;

  SELECT [t].[creation_date] FROM [dbo].[event_coupons] t
  INNER JOIN @inserted1 i ON ([t].[Id] = [i].[Id])
  ORDER BY [i].[_Position];

  DECLARE @inserted4 TABLE ([Id] char(8), [_Position] [int]);
  MERGE [dbo].[event_fields] USING (
  VALUES (@p51, @p52, @p53, @p54, @p55, 0),
  (@p56, @p57, @p58, @p59, @p60, 1),
  (@p61, @p62, @p63, @p64, @p65, 2)) AS i ([Id], [id_event], [id_field], [last_modified], [Removed], _Position) ON 1=0
  WHEN NOT MATCHED THEN
  INSERT ([Id], [id_event], [id_field], [last_modified], [Removed])
  VALUES (i.[Id], i.[id_event], i.[id_field], i.[last_modified], i.[Removed])
  OUTPUT INSERTED.[Id], i._Position
  INTO @inserted4;

  SELECT [t].[creation_date] FROM [dbo].[event_fields] t
  INNER JOIN @inserted4 i ON ([t].[Id] = [i].[Id])
  ORDER BY [i].[_Position];

  INSERT INTO [dbo].[event_products] ([Id], [id_event], [last_modified], [name], [Removed], [value])
  VALUES (@p66, @p67, @p68, @p69, @p70, @p71);
  SELECT [creation_date]
  FROM [dbo].[event_products]
  WHERE @@ROWCOUNT = 1 AND [Id] = @p66;

To make it clearer, I am inserting 1 event that you may have: address, several fields, coupons and products. The event itself with the address I am managing to save however when having to save the event with 2 or more products, or 2 or more coupons, or 2 or more additional fields, I get the error mentioned above.

The algorithm works when I create an event that has an address, an additional field, a coupon and a product. However, when one of these fields is greater than one, the exception is thrown.

I need help to solve this problem, thank you already. The question is, is there any way to make the change without me having to modify the default configuration of my bank? I'm using asp net core 2.2.

c#
sql
asp.net-core
asp.net-web-api
entity-framework-core
asked on Stack Overflow Feb 26, 2020 by Erik hz • edited Feb 26, 2020 by Erik hz

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0