Alg*_*das 71 c# entity-framework sql-server-2008 entity-framework-6
我有一个主键"Id"的实体,它是Guid:
public class FileStore
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
还有一些配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<FileStore>().Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
Run Code Online (Sandbox Code Playgroud)
当我尝试插入记录时,我收到以下错误:
无法将值NULL插入列'Id',表'FileStore'; 列不允许空值.INSERT失败.\ r \n语句已终止.
我不想手动生成Guid.我只想插入一条记录Id
并由SQL Server生成.如果我设置.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
,则Id
列不是SQL Server中的标识列.
如何配置实体框架以在SQL Server中自动生成Guid?
小智 92
除了将这些属性添加到您的Id列之外:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
Run Code Online (Sandbox Code Playgroud)
在您的迁移中,您应该更改您CreateTable
的defaultValueSQL
属性以添加到您的列,即:
Id = c.Guid(nullable: false, identity: true, defaultValueSql: "newsequentialid()"),
Run Code Online (Sandbox Code Playgroud)
这将使您无需手动触摸数据库,正如您在评论中指出的那样,您希望使用Code First避免使用该数据库.
小智 16
试试这个 :
public class FileStore
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
你可以查看这篇SO帖子.
您可以将数据库中Id的默认值设置为newsequentialid()或newid().然后EF的身份配置应该工作.
它发生在我之前.
当表已经创建并且我.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
稍后添加时,代码迁移在某种程度上无法为Guid列分配默认值.
修复:
我们所需要的只是转到数据库,选择Id列并newsequentialid()
手动添加Default Value or Binding
.
无需更新dbo .__ MigrationHistory表.
希望能帮助到你.
添加的解决方案New Guid()
通常不优选,因为在理论上是,你可能会得到一个意外重复的可能性.
您不必担心在数据库中直接编辑.所有实体框架都是自动化我们数据库工作的一部分.
翻译
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
Run Code Online (Sandbox Code Playgroud)
成
[Id] [uniqueidentifier] NOT NULL DEFAULT newsequentialid(),
Run Code Online (Sandbox Code Playgroud)
如果我们的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; }
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个映射配置类
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();
}
}
Run Code Online (Sandbox Code Playgroud)
当您像这样执行add-migration时,这会在初始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);
Run Code Online (Sandbox Code Playgroud)
注意: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);
Run Code Online (Sandbox Code Playgroud)
注意:我们重写了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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
实体框架 \xe2\x80\x93 使用 Guid 作为主键
\n\n使用实体框架时,使用 Guid 作为表主键比使用整数需要更多的工作。在您\xe2\x80\x99 阅读/被展示如何操作之后,设置过程非常简单。
\n\n代码优先和数据库优先方法的过程略有不同。这篇文章讨论了这两种技术。
\n\n\n\n代码优先
\n\n采用代码优先方法时,使用 Guid 作为主键很简单。创建实体时,将 DatabaseGenerate 属性添加到主键属性中,如下所示;
\n\n[DatabaseGenerated(DatabaseGeneratedOption.Identity)]\npublic Guid Id { get; set; }\n
Run Code Online (Sandbox Code Playgroud)\n\n实体框架将按照您的预期创建列,并具有主键和 uniqueidentifier 数据类型。
\n\ncodefirst-defaultvalue\n
Run Code Online (Sandbox Code Playgroud)\n\n另请注意,非常重要的是,该列的默认值已设置为(newsequentialid())
。这会为每一行生成一个新的顺序(连续)Guid。如果您愿意,可以将其更改为newid()
),这将导致每个新行都有一个完全随机的 Guid。每次删除并重新创建数据库时,该信息都会被清除,因此在采用数据库优先方法时效果更好。
数据库优先
\n\n数据库优先方法与代码优先方法类似,但您\xe2\x80\x99 必须手动编辑模型才能使其工作。
\n\n确保在执行任何操作之前编辑主键列并添加 (newsequentialid()) 或 (newid()) 函数作为默认值。
\n\n\n\n接下来,打开 EDMX 图,选择适当的属性并打开属性窗口。确保 StoreGeneratePattern 设置为标识。
\n\ndatabasefirst-model\n
Run Code Online (Sandbox Code Playgroud)\n\n无需在代码中为您的实体提供 ID,该 ID 将在实体提交到数据库后自动为您填充;
\n\nusing (ApplicationDbContext context = new ApplicationDbContext())\n{\n var person = new Person\n {\n FirstName = "Random",\n LastName = "Person";\n };\n\n context.People.Add(person);\n context.SaveChanges();\n Console.WriteLine(person.Id);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n重要提示:您的 Guid 字段必须是主键,否则不起作用。实体框架会给你一个相当神秘的错误消息!
\n\n概括
\n\nGuid(全局唯一标识符)可以轻松地用作实体框架中的主键。为此需要付出一些额外的努力,具体取决于您采用的方法。使用代码优先方法时,请将 DatabaseGeneerated 属性添加到关键字段。采用“数据库优先”方法时,请在模型上将 StoredGeneratePattern 显式设置为 Identity。
\n\n[1]: https://i.stack.imgur.com/IxGdd.png\n[2]: https://i.stack.imgur.com/Qssea.png\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
96065 次 |
最近记录: |