gpt4 book ai didi

c# - EF,代码优先 - 如何在插入时设置自定义 Guid 标识值

转载 作者:可可西里 更新时间:2023-11-01 08:28:13 25 4
gpt4 key购买 nike

在处理以 Guid 作为主键的数据库中插入新实体时,我遇到了以下问题 - EF 5 with Code first 方法。

我知道有很多类似的话题,因为我为这个问题徘徊了几个小时,但我找不到与这个问题相关的话题。

例如,我的 POCO 类是:

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

[Required]
[MaxLength(50)]
public string Name { get; set; }

[Required]
[Display(Name = "Role code")]
[MaxLength(20)]
public string RoleCode { get; set; }

[Display(Name = "Entities Assigned")]
[InverseProperty("Role")]
public List<Entity> Entities { get; set; }
}

RoleCode 和 Name 只是文本数据,可以在管理面板中编辑,所以不要考虑这些字段名称。

添加新实体时,我没有指定主键值。到目前为止一切顺利,这里一切正常。作为一个需要取值且自动生成值的主键字段,应该不会一直指定Id,但如果我设置了一个值,它应该被保留(如果启用了标识插入)。

但在某些情况下,我想指定一个主键值,例如用值对我的数据库进行初始播种。我需要它用于以后的处理 - 可以说我需要那个特定的 Guid 在那里。所以如果我的配置类中有:

// Initial data seed
protected override void Seed(WebPortalDbContext context)
{
context.MenuItems.AddOrUpdate(
m => m.Id,
new EntityRole {Id = new Guid("268bf332-910e-4ea1-92f8-1ac0611f4c62"), Name = "Some name", RoleCode = "SN"},
);
}

即使我进行常规添加,Guid 键设置也不起作用:

using (var context = new MyDBContext())
{
context.MenuItems.Add(
new Entity() {Id = new Guid("<some guid>"), Name = "fooname" /*some other values*/}
);

context.SaveChanges();
}

我在 SQL Server 跟踪中的内容是:

exec sp_executesql N'declare @generated_keys table([Id] uniqueidentifier)
insert [dbo].[EntityRoles]([Name], [RoleCode])
output inserted.[Id] into @generated_keys
values (@0, @1)
select t.[Id]
from @generated_keys as g join [dbo].[EntityRoles] as t on g.[Id] = t.[Id]
where @@ROWCOUNT > 0',N'@0 nvarchar(50),@1 nvarchar(20)',@0=N'Chief Captain',@1=N'CO1'

这里很明显,新的 Guid 值只是没有从 EF SQL 生成器发送到 SQL Server,所以问题出在 EF。

所以我删除了 DatabaseGeneratedOption.Identity 属性,然后就可以了,但是我失去了 Id key 的自动生成,这对我不起作用,因为这种情况非常罕见。

目前我唯一的解决方案:

我最终是覆盖 DBContext 的 SaveChanges() 方法并修改所有要添加状态的实体(我的想法来自 here ):

/// <summary> Custom processing when saving entities in changetracker </summary>
public override int SaveChanges()
{
// recommended to explicitly set New Guid for appropriate entities -- http://msdn.microsoft.com/en-us/library/dd283139.aspx
foreach (var entry in ChangeTracker.Entries().Where(e => e.State == EntityState.Added))
{
var t = entry.Entity.GetType();
if (t.GetProperty("Id") == null)
continue;

var info = t.GetProperty("Id").GetCustomAttributes(typeof (DatabaseGeneratedAttribute), true).Cast<DatabaseGeneratedAttribute>();
if (!info.Any() || info.Single().DatabaseGeneratedOption != DatabaseGeneratedOption.Identity)
{
if (t.GetProperty("Id").PropertyType == typeof(Guid) && (Guid)t.GetProperty("Id").GetValue(entry.Entity, null) == Guid.Empty)
t.GetProperty("Id").SetValue(entry.Entity, Guid.NewGuid(), null);
}
}
return base.SaveChanges();
}

与此相结合,应删除所有 DatabaseGeneratedOption。所有模型都有名为“Id”的主键,遵循命名约定的最佳实践主题之一。

但这看起来不是很优雅的 workaronud,因为我认为 EF5 应该能够处理这种情况。如果身份插入打开,它适用于 Int 身份。

那么有人知道如何更好地解决这个问题吗?

最佳答案

因为它是一个 GUID,所以您执行此操作的简单方法是在您的类中有一个构造函数,例如

public EntityRole()
{
Id = Guid.NewGuid();
}

并删除 The database generated 选项或将其更改为 DatabaseGeneratedOption.None。

关于c# - EF,代码优先 - 如何在插入时设置自定义 Guid 标识值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13743483/

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