programing

Entity Framework 6 GUID를 기본 키로 : 'Id'열, 'FileStore'테이블에 NULL 값을 삽입 할 수 없습니다.

nasanasas 2020. 11. 1. 18:11
반응형

Entity Framework 6 GUID를 기본 키로 : 'Id'열, 'FileStore'테이블에 NULL 값을 삽입 할 수 없습니다. 열은 널을 허용하지 않습니다.


Guid 인 기본 키 "Id"가있는 엔티티가 있습니다.

public class FileStore
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Path { get; set; }
}

그리고 일부 구성 :

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<FileStore>().Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    base.OnModelCreating(modelBuilder);
}

레코드를 삽입하려고하면 다음 오류가 발생합니다.

'Id'열, 'FileStore'테이블에 NULL 값을 삽입 할 수 없습니다. 열은 널을 허용하지 않습니다. INSERT가 실패했습니다. \ r \ n 문이 종료되었습니다.

수동으로 Guid를 생성하고 싶지 않습니다. 레코드를 삽입하고 IdSQL Server에서 생성 하고 싶습니다 . 내가 설정 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)하면 Id열은 SQL Server의 ID 열이 아닙니다.

SQL Server에서 Guid를 자동 생성하도록 Entity Framework를 구성하려면 어떻게해야합니까?


이러한 속성을 Id 열에 추가하는 것 외에도 :

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }

마이그레이션 CreateTable에서 defaultValueSQL속성을 열에 추가하도록 변경해야 합니다 .

Id = c.Guid(nullable: false, identity: true, defaultValueSql: "newsequentialid()"),

이렇게하면 주석에서 지적했듯이 Code First로 피하고 싶은 데이터베이스를 수동으로 만질 필요가 없습니다.


이 시도 :

public class FileStore
 {
   [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
   public Guid Id { get; set; }
   public string Name { get; set; }
   public string Path { get; set; }
 }

SO 게시물을 확인할 수 있습니다 .


db의 Id 기본값을 newsequentialid () 또는 newid ()로 설정할 수 있습니다. 그러면 EF의 ID 구성이 작동합니다.


전에 나에게 일어났습니다.

테이블이 생성되고 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)나중에 추가 할 때 코드 마이그레이션에서 어떻게 든 Guid 열에 대한 기본값을 할당 할 수 없습니다.

수정 사항 :

필요한 것은 데이터베이스로 이동하여 Id 열을 선택하고에 newsequentialid()수동으로 추가 하는 것 Default Value or Binding입니다.

dbo .__ MigrationHistory 테이블을 업데이트 할 필요가 없습니다.

도움이 되었기를 바랍니다.


추가의 솔루션은 New Guid()이론이 있기 때문에 일반적으로 바람직하지 않다 하다 실수로 중복을 얻을 수 있다는 가능성은.


그리고 데이터베이스에서 직접 편집하는 것에 대해 걱정할 필요가 없습니다. Entity Framework가하는 일은 데이터베이스 작업의 일부를 자동화하는 것입니다.

번역 중

.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)

으로

[Id] [uniqueidentifier] NOT NULL DEFAULT newsequentialid(),

EF가 한 가지를 놓치고 기본값을 추가하지 않은 경우 수동으로 추가하십시오.


이것은 나를 위해 작동합니다 (Azure 없음), dev 서버의 SQL 2008 R2 또는 로컬 워크 스테이션의 localdb \ mssqllocaldb. 참고 : 엔터티는 Create, CreateBy, Modified, ModifiedBy 및 Version 열을 추가합니다.

public class Carrier : Entity
{
    public Guid Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
}

그런 다음 매핑 구성 클래스를 만듭니다.

public class CarrierMap : EntityTypeConfiguration<Carrier>
{
    public CarrierMap()
    {
        HasKey(p => p.Id);

        Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        Property(p => p.Code)
            .HasMaxLength(4)
            .IsRequired()
            .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsClustered = true, IsUnique = true }));

        Property(p => p.Name).HasMaxLength(255).IsRequired();
        Property(p => p.Created).HasPrecision(7).IsRequired();
        Property(p => p.Modified)
            .HasColumnAnnotation("IX_Modified", new IndexAnnotation(new IndexAttribute()))
            .HasPrecision(7)
            .IsRequired();
        Property(p => p.CreatedBy).HasMaxLength(50).IsRequired();
        Property(p => p.ModifiedBy).HasMaxLength(50).IsRequired();
        Property(p => p.Version).IsRowVersion();
    }
}

이렇게하면 다음과 같이 추가 마이그레이션을 실행할 때 초기 DbMigration에 Up 메서드가 생성됩니다.

        CreateTable(
            "scoFreightRate.Carrier",
            c => new
                {
                    Id = c.Guid(nullable: false, identity: true),
                    Code = c.String(nullable: false, maxLength: 4),
                    Name = c.String(nullable: false, maxLength: 255),
                    Created = c.DateTimeOffset(nullable: false, precision: 7),
                    CreatedBy = c.String(nullable: false, maxLength: 50),
                    Modified = c.DateTimeOffset(nullable: false, precision: 7,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "IX_Modified",
                                new AnnotationValues(oldValue: null, newValue: "IndexAnnotation: { }")
                            },
                        }),
                    ModifiedBy = c.String(nullable: false, maxLength: 50),
                    Version = c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion"),
                })
            .PrimaryKey(t => t.Id)
            .Index(t => t.Code, unique: true, clustered: true);

참고 : Id 열에는 기본값이 없으므로 걱정하지 마십시오.

이제 Update-Database를 실행하면 다음과 같이 데이터베이스에 테이블 정의가 생성됩니다.

CREATE TABLE [scoFreightRate].[Carrier] (
    [Id]         UNIQUEIDENTIFIER   DEFAULT (newsequentialid()) NOT NULL,
    [Code]       NVARCHAR (4)       NOT NULL,
    [Name]       NVARCHAR (255)     NOT NULL,
    [Created]    DATETIMEOFFSET (7) NOT NULL,
    [CreatedBy]  NVARCHAR (50)      NOT NULL,
    [Modified]   DATETIMEOFFSET (7) NOT NULL,
    [ModifiedBy] NVARCHAR (50)      NOT NULL,
    [Version]    ROWVERSION         NOT NULL,
    CONSTRAINT [PK_scoFreightRate.Carrier] PRIMARY KEY NONCLUSTERED ([Id] ASC)
);


GO
CREATE UNIQUE CLUSTERED INDEX [IX_Code]
    ON [scoFreightRate].[Carrier]([Code] ASC);

참고 : 개발자가 테이블에 더 나은 클러스터형 인덱스를 설정하도록 권장하므로 기본 키를 클러스터형 인덱스로 만들지 않도록 SqlServerMigrationSqlGenerator를 재정의했습니다.

public class OurMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    protected override void Generate(AddPrimaryKeyOperation addPrimaryKeyOperation)
    {
        if (addPrimaryKeyOperation == null) throw new ArgumentNullException("addPrimaryKeyOperation");
        if (!addPrimaryKeyOperation.Table.Contains("__MigrationHistory"))
            addPrimaryKeyOperation.IsClustered = false;
        base.Generate(addPrimaryKeyOperation);
    }

    protected override void Generate(CreateTableOperation createTableOperation)
    {
        if (createTableOperation == null) throw new ArgumentNullException("createTableOperation");
        if (!createTableOperation.Name.Contains("__MigrationHistory"))
            createTableOperation.PrimaryKey.IsClustered = false;
        base.Generate(createTableOperation);
    }

    protected override void Generate(MoveTableOperation moveTableOperation)
    {
        if (moveTableOperation == null) throw new ArgumentNullException("moveTableOperation");
        if (!moveTableOperation.CreateTableOperation.Name.Contains("__MigrationHistory")) moveTableOperation.CreateTableOperation.PrimaryKey.IsClustered = false;
        base.Generate(moveTableOperation);
    }
}

에 따르면 서비스가 추가되면 DatabaseGeneratedOption.Identity은 특정 마이그레이션에 의해 감지되지 테이블 내가으로 실행하는 경우, 이는 만들었습니다. 그래서 데이터베이스와 특정 마이그레이션을 삭제하고 새 마이그레이션을 추가하고 마지막으로 데이터베이스를 업데이트하면 모든 것이 예상대로 작동합니다. EF 6.1, SQL2014 및 VS2013을 사용하고 있습니다.


Entity Framework – Guid를 기본 키로 사용

Using a Guid as your tables primary key, when using Entity Framework, requires a little more effort than when using a integer. The setup process is straightforward, after you’ve read/been shown how to do it.

The process is slightly different for the Code First and Database First approaches. This post discusses both techniques.

enter image description here

Code First

Using a Guid as the primary key when taking the code first approach is simple. When creating your entity, add the DatabaseGenerated attribute to your primary key property, as shown below;

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }

Entity framework will create the column as you would expect, with a primary key and uniqueidentifier data type.

codefirst-defaultvalue

Also notice, very important, that the default value on the column has been set to (newsequentialid()). This generates a new sequential (continuous) Guid for each row. If you were so inclined, you could change this to newid()), which would result in a completely random Guid for each new row. This will be cleared each time your database gets dropped and re-created, so this works better when taking the Database First approach.

Database First

The database first approach follows a similar line to the code first approach, but you’ll have to manually edit your model to make it work.

Ensure that you edit the primary key column and add the (newsequentialid()) or (newid()) function as the default value before doing anything.

enter image description here

Next, open you EDMX diagram, select the appropriate property and open the properties window. Ensure that StoreGeneratedPattern is set to identity.

databasefirst-model

No need to give your entity an ID in your code, that will be populated for you automatically after the entity has been commited to the database;

using (ApplicationDbContext context = new ApplicationDbContext())
{
    var person = new Person
                     {
                         FirstName = "Random",
                         LastName = "Person";
                     };

    context.People.Add(person);
    context.SaveChanges();
    Console.WriteLine(person.Id);
}

Important Note: Your Guid field MUST be a primary key, or this does not work. Entity Framework will give you a rather cryptic error message!

Summary

Guid (Globally Unique Identifiers) can easily be used as primary keys in Entity Framework. A little extra effort is required to do this, depending on which approach you are taking. When using the code first approach, add the DatabaseGenerated attribute to your key field. When taking the Database First approach, explicitly set the StoredGeneratedPattern to Identity on your model.

[1]: https://i.stack.imgur.com/IxGdd.png
[2]: https://i.stack.imgur.com/Qssea.png

If you do Code-First and already have a Database:

public override void Up()
{
    AlterColumn("dbo.MyTable","Id", c =>  c.Guid(nullable: false, identity: true, defaultValueSql: "newsequentialid()"));
}

You can not. You will / do break a lot of things. Like relationships. WHich rely on the number being pulled back which EF can not do in the way you set it up. THe price for breaking every pattern there is.

Generate the GUID in the C# layer, so that relationships can continue working.


And what something like this?

public class Carrier : Entity
{
    public Carrier()
    {
         this.Id = Guid.NewGuid();
    }  
    public Guid Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
}

참고URL : https://stackoverflow.com/questions/23081096/entity-framework-6-guid-as-primary-key-cannot-insert-the-value-null-into-column

반응형