gpt4 book ai didi

c# - 带有 DatabaseGeneratedOption.Identity Guid Id 的 EF6 实体强制插入我的 Id 值

转载 作者:搜寻专家 更新时间:2023-10-30 22:28:42 26 4
gpt4 key购买 nike

我正在尝试使用 EF 导出/导入 DbContext 的现有数据库。在此上下文中,有几个实体具有 Guid Id 属性和由 ModelBuilder 定义的 DatabaseGeneratedOption.Identity。当我重新导入实体时,我想使用序列化对象中的 Id 值,但当我保存更改时它总是生成一个新的 Id 值。在这种情况下,有什么办法可以强制 EF 使用我的 Id 值吗?我知道 DatabaseGeneratedOption.None 将允许我这样做,但我将始终负责生成 Id。我知道在不使用顺序 Guid 的情况下会出现索引分段问题,所以我不想这样做。

是我运气不好还是有人找到了窍门?

更新:我们决定简单地将所有 Guid Id 从 DatabaseGeneratedOption.Identity 更改为 DatabaseGenerationOption.None 并自己提供 Id。尽管这会导致索引碎片化,但我们不认为这会成为我们较小的表的问题。

最佳答案

您可以通过定义从基础上下文派生的两个上下文来实现您想要的。一个上下文使用 DatabaseGeneratedOption.Identity 定义其键,另一个使用 DatabaseGeneratedOption.None。第一个是您的常规应用程序的上下文。

这是可能的,因为 Guid 主键不是真正的标识列。它们只是具有默认约束的列,因此可以不带值插入它们,或者值而无需设置 identity_insert .

为了证明这是可行的,我使用了一个非常简单的类:

public class Planet
{
public Guid ID { get; set; }
public string Name { get; set; }
}

基本上下文:

public abstract class BaseContext : DbContext
{
private readonly DatabaseGeneratedOption _databaseGeneratedOption;

protected BaseContext(string conString, DatabaseGeneratedOption databaseGeneratedOption)
: base(conString)
{
this._databaseGeneratedOption = databaseGeneratedOption;
}

public DbSet<Planet> Planets { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Planet>().HasKey(p => p.ID);
modelBuilder.Entity<Planet>().Property(p => p.ID)
.HasDatabaseGeneratedOption(this._databaseGeneratedOption);
base.OnModelCreating(modelBuilder);
}
}

上下文子类:

public class GenerateKeyContext : BaseContext
{
public GenerateKeyContext(string conString)
: base(conString, DatabaseGeneratedOption.Identity)
{ }
}

public class InsertKeyContext : BaseContext
{
public InsertKeyContext(string conString)
: base(conString, DatabaseGeneratedOption.None)
{ }
}

我首先运行一些代码来创建和播种源数据库:

var db1 = @"Server=(localDB)\MSSQLLocalDB;Integrated Security=true;Database=GuidGen";
var db2 = @"Server=(localDB)\MSSQLLocalDB;Integrated Security=true;Database=GuidInsert";

// Set initializers:
// 1. just for testing.
Database.SetInitializer(new DropCreateDatabaseAlways<GenerateKeyContext>());
// 2. prevent model check.
Database.SetInitializer<InsertKeyContext>(null);

using (var context = new GenerateKeyContext(db1))
{
var earth = new Planet { Name = "Earth", };
var mars = new Planet { Name = "Mars", };
context.Planets.Add(earth);
context.Planets.Add(mars);

context.SaveChanges();
}

和一个目标数据库:

using (var context = new GenerateKeyContext(db2))
{
context.Database.Initialize(true);
}

最后,这是执行实际工作的代码:

var planets = new List<UserQuery.Planet>();
using (var context = new GenerateKeyContext(db1))
{
planets = context.Planets.AsNoTracking().ToList();
}
using (var context = new InsertKeyContext(db2))
{
context.Planets.AddRange(planets);
context.SaveChanges();
}

现在在两个数据库中,您将看到两条具有相同键值的记录。

您可能想知道:为什么我不能使用一个上下文类,并在有或没有 Identity 选项的情况下构造它?这是因为 EF 仅为上下文类型构建一次 EDM 模型并将其存储在 AppDomain 中。因此,您首先使用的选项将决定 EF 将哪个模型用于您的上下文类。

关于c# - 带有 DatabaseGeneratedOption.Identity Guid Id 的 EF6 实体强制插入我的 Id 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47227048/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com