.Net Core EF - 当自动向表中插入数据时,自动 sql 代码可能会使用没有 id 属性的合并导致错误

问题描述 投票:0回答:1

我正在使用 this 项目作为我的 web API 的模板。我已经用它们的主键和外键创建了表,并用数据填充了它们。当我尝试将数据添加到数据库中的另一个新表时,由于某种我无法理解的原因,框架忽略了自动索引属性“Id”。此错误导致自动生成的 SQL 语句执行失败,因为没有提供 ID 索引,假设它不是空属性。新数据未添加到表中,尽管之前对其他表的数据更新已成功完成。

表的实体类实现了一个接口和一个对象

public interface IAggregateRoot
    {
    }
public abstract class BaseEntity<T>
    {
        public virtual int Id { get; protected set; }
    }

只有“Id”作为属性。

在这里你可以看到课程,

public class Shop_Empleado : BaseEntity<Shop_Empleado>, IAggregateRoot
    {
        public long Ruc { get; set; }
        public string Nombre1 { get; set; }
        public string Nombre2 { get; set; }
        public string Apellido1 { get; set; }
        public string Apellido2 { get;set; }
        public int Edad { get; set; }
        public string Direccion1 { get; set; }
        public string Direccion2 { get; set; }
        public string Nacionalidad { get; set; }
        public string Telefono1 { get; set; }
        public string Telefono2 { get; set;}
        public string Email { get; set; }
        public string Puesto { get; set; }
        public Shop_Local? Shop_Local { get; set; }
        public int LocalId { get; set; }
        public double Salario { get; set; }
        //public DateTime Fecha_Ingreso { get; set; }
        public bool Iess { get; set; }

        public Shop_Empleado(long Ruc, string Nombre1, string Nombre2, string Apellido1, string Apellido2, 
            int Edad, string Direccion1, string Direccion2, string Nacionalidad, string Telefono1,
            string Puesto, double Salario, bool Iess, string Telefono2 = "-",
            string Email = "-", int LocalId = 1)
        {
            this.Ruc = Ruc;
            this.Nombre1 = Nombre1;
            this.Nombre2 = Nombre2;
            this.Apellido1 = Apellido1;
            this.Apellido2 = Apellido2;
            this.Edad = Edad;
            this.Direccion1 = Direccion1;
            this.Direccion2 = Direccion2;
            this.Nacionalidad = Nacionalidad;
            this.Telefono1 = Telefono1;
            this.Telefono2 = Telefono2;
            this.Email = Email;
            this.Puesto = Puesto;
            this.Salario = Salario;
            //this.Fecha_Ingreso = Fecha_Ingreso;
            this.Iess = Iess;
            this.LocalId = LocalId;
        }

配置,

public class Shop_Empleado_Configurations : IEntityTypeConfiguration<Shop_Empleado>
    {
        public void Configure(EntityTypeBuilder<Shop_Empleado> builder)
        {
            builder.ToTable("Shop_Empleado");

            builder.Property(ai => ai.Id)
                .UseHiLo("shop_empleado_hilo")
                .IsRequired();

            builder.Property(ai => ai.Ruc)
                .IsRequired(true)
                .HasColumnType("bigint");

            builder.Property(ai => ai.Nombre1)
                .IsRequired(true)
                .HasMaxLength(25);

            builder.Property(ai => ai.Nombre2)
                .IsRequired(true)
                .HasMaxLength(25);

            builder.Property(ai => ai.Apellido1)
                .IsRequired(true)
                .HasMaxLength(25);

            builder.Property(ai => ai.Apellido2)
                .IsRequired(true)
                .HasMaxLength(25);

            builder.Property(ai => ai.Edad)
                .IsRequired(true)
                .HasColumnType("integer");

            builder.Property(ai => ai.Direccion1)
                .IsRequired(true)
                .HasMaxLength(90);

            builder.Property(ai => ai.Direccion2)
                .IsRequired(true)
                .HasMaxLength(90);

            builder.Property(ai => ai.Nacionalidad)
                .IsRequired(true)
                .HasMaxLength(30);

            builder.Property(ai => ai.Telefono1)
                .IsRequired(true)
                .HasMaxLength(12);

            builder.Property(ai => ai.Telefono2)
                .IsRequired(false)
                .HasMaxLength(12);

            builder.Property(ai => ai.Email)
                .IsRequired(false)
                .HasMaxLength(100);

            builder.Property(ai => ai.Puesto)
                .IsRequired(true)
                .HasMaxLength(35);

            builder.HasOne(ai => ai.Shop_Local)
                .WithMany()
                .HasPrincipalKey(ci => ci.Id)
                .IsRequired(true);

            builder.Property(ai => ai.Salario)
                .IsRequired (true)
                .HasColumnType ("decimal(6,2)");

            //builder.Property(ai => ai.Fecha_Ingreso)
            //    .IsRequired (true)
            //    .HasColumnType ("datetime2(7)");

            builder.Property(ai => ai.Iess)
                .IsRequired(true)
                .HasColumnType("bit");


        }

和 InitialModel

protected override void Up(MigrationBuilder migrationBuilder)
        {
//Creacion Tabla Empleado
            migrationBuilder.CreateSequence(
                name: "shop_empleado_hilo",
                incrementBy: 10);

            migrationBuilder.CreateTable(
                name: "Shop_Empleado",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false),
                    Ruc = table.Column<long>(type: "bigint", maxLength: 13, nullable: false),
                    Nombre1 = table.Column<string>(type: "nvarchar(25)", maxLength: 35, nullable: false),
                    Nombre2 = table.Column<string>(type: "nvarchar(25)", maxLength: 35, nullable: false),
                    Apellido1 = table.Column<string>(type: "nvarchar(25)", maxLength: 35, nullable: false),
                    Apellido2 = table.Column<string>(type: "nvarchar(25)", maxLength: 35, nullable: false),
                    Edad = table.Column<int>(type: "int", nullable: false),
                    Direccion1 = table.Column<string>(type: "nvarchar(90)", maxLength: 90, nullable: false),
                    Direccion2 = table.Column<string>(type: "nvarchar(90)", maxLength: 90, nullable: false),
                    Nacionalidad = table.Column<int>(type: "nvarchar(30)", maxLength: 30, nullable: false),
                    Telefono1 = table.Column<string>(type: "nvarchar(12)", maxLength: 12, nullable: false),
                    Telefono2 = table.Column<string>(type: "nvarchar(12)", maxLength: 12, nullable: true),
                    Email = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
                    Puesto = table.Column<string>(type: "nvarchar(35)", maxLength: 35, nullable: false),
                    LocalId = table.Column<int>(type: "int", nullable: false),
                    Salario = table.Column<double>(type: "decimal(6,2)", nullable: false),
                    //Fecha_Ingreso = table.Column<DateTime>(type: "datetime2(7)", maxLength: 7, nullable: false),
                    Iess = table.Column<bool>(type: "bit", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Shop_Empleado", x => x.Id);
                    //table.ForeignKey("FK_Shop_Local_Shop_LocalId",
                    //    column: x => x.LocalId,
                    //    principalTable: "Shop_Local",
                    //    principalColumn: "Id",
                    //    onDelete: ReferentialAction.Cascade);
                });
        }

创建数据库表和配置实体的文件。文件模板已成功用于其他表和对象。对于这个特定实体,自动生成的 SQL 会忽略 ID 属性。

错误提示:

SELECT CASE
    WHEN EXISTS (
        SELECT 1
        FROM [Shop_Empleado] AS [s]) THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END
Microsoft.EntityFrameworkCore.Database.Command: Information: Executed DbCommand (7ms) [Parameters=[@p0='?' (Size = 25), @p1='?' (Size = 25), @p2='?' (Size = 90), @p3='?' (Size = 90), @p4='?' (DbType = Int32), @p5='?' (Size = 100), @p6='?' (DbType = Boolean), @p7='?' (DbType = Int32), @p8='?' (Size = 30), @p9='?' (Size = 25), @p10='?' (Size = 25), @p11='?' (Size = 35), @p12='?' (DbType = Int64), @p13='?' (Precision = 6) (Scale = 2) (DbType = Decimal), @p14='?' (Size = 12), @p15='?' (Size = 12), @p16='?' (Size = 25), @p17='?' (Size = 25), @p18='?' (Size = 90), @p19='?' (Size = 90), @p20='?' (DbType = Int32), @p21='?' (Size = 100), @p22='?' (DbType = Boolean), @p23='?' (DbType = Int32), @p24='?' (Size = 30), @p25='?' (Size = 25), @p26='?' (Size = 25), @p27='?' (Size = 35), @p28='?' (DbType = Int64), @p29='?' (Precision = 6) (Scale = 2) (DbType = Decimal), @p30='?' (Size = 12), @p31='?' (Size = 12), @p32='?' (Size = 25), @p33='?' (Size = 25), @p34='?' (Size = 90), @p35='?' (Size = 90), @p36='?' (DbType = Int32), @p37='?' (Size = 100), @p38='?' (DbType = Boolean), @p39='?' (DbType = Int32), @p40='?' (Size = 30), @p41='?' (Size = 25), @p42='?' (Size = 25), @p43='?' (Size = 35), @p44='?' (DbType = Int64), @p45='?' (Precision = 6) (Scale = 2) (DbType = Decimal), @p46='?' (Size = 12), @p47='?' (Size = 12)], CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
MERGE [Shop_Empleado] USING (
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, 0),
(@p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31, 1),
(@p32, @p33, @p34, @p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46, @p47, 2)) AS i ([Apellido1], [Apellido2], [Direccion1], [Direccion2], [Edad], [Email], [Iess], [LocalId], [Nacionalidad], [Nombre1], [Nombre2], [Puesto], [Ruc], [Salario], [Telefono1], [Telefono2], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Apellido1], [Apellido2], [Direccion1], [Direccion2], [Edad], [Email], [Iess], [LocalId], [Nacionalidad], [Nombre1], [Nombre2], [Puesto], [Ruc], [Salario], [Telefono1], [Telefono2])
VALUES (i.[Apellido1], i.[Apellido2], i.[Direccion1], i.[Direccion2], i.[Edad], i.[Email], i.[Iess], i.[LocalId], i.[Nacionalidad], i.[Nombre1], i.[Nombre2], i.[Puesto], i.[Ruc], i.[Salario], i.[Telefono1], i.[Telefono2])
OUTPUT INSERTED.[Id], i._Position;
'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.3\System.Reflection.Metadata.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Microsoft.EntityFrameworkCore.Update: Error: An exception occurred in the database while saving changes for context type 'Infrastructure.Data.Shop_Context'.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'Id', table 'SagaMotors_API.CatalogDb.dbo.Shop_Empleado'; column does not allow nulls. UPDATE fails.
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
   at Microsoft.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
   at Microsoft.Data.SqlClient.SqlDataReader.ReadAsyncExecute(Task task, Object state)
   at Microsoft.Data.SqlClient.SqlDataReader.InvokeAsyncCall[T](SqlDataReaderAsyncCallContext`1 context)
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetAsync(Int32 startCommandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
ClientConnectionId:0b3a38fc-9621-4ae5-8cda-5cbef60dd43c
Error Number:515,State:2,Class:16

我对 C# 和 .NET 并不陌生,也不是专业人士。有人可以帮我解决这个恼人的问题吗?

我尝试使用显示的文件模板,因为它们成功地创建并向表实体添加了数据。我希望框架自动生成与其他情况相同的 SQL 语句,但它忽略了“ID”属性。该错误指出 ID 不能为 null,但在声明中从未给出 ID 的值。

另外,我不知道为什么 SQL 语句在应该自动索引该属性时尝试输出插入的 ID。正如您在促销中看到的那样,SQL 从未在语句中为 ID 提供任何值。

.net attributes sql-update ado.net
1个回答
0
投票

所以,经过八个小时的良好休息并仔细阅读代码后,我发现问题出在我的表引用的外键上。问题的核心在于配置文件中是否配置了类型、键和数据要求。正如您在给定代码中看到的那样,我错误地尝试在“LocalId”中设置主键,因为我必须使用外键。此错误使 .NET Core 在插入数据时尝试使用 Merge Sql 操作。此外,编码中的错误使 .NET 忽略了打算作为默认索引和主键的 ID 属性。正确的代码是:

builder.HasOne(ai => ai.Shop_Local)
            .WithMany()
            .HasForeignKey(ci => ci.LocalId)
            .IsRequired(true);

请注意,使用方法“HasForeingKey()”代替“HasPrimaryKey()”,并且实体类的成员“LocalId”正在替换“Id”成员。

© www.soinside.com 2019 - 2024. All rights reserved.