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

C# EF,代码优先-如何在插入时设置自定义Guid标识值,c#,entity-framework,.net-4.0,C#,Entity Framework,.net 4.0,我在处理在数据库中插入新实体时遇到了以下问题,该数据库将Guid作为主键-ef5,使用代码优先的方法 我知道有很多类似的主题,因为我在这个问题上花了几个小时,但我找不到这个问题的主题 例如,我的POCO类是: public class EntityRole : IAdminModel { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; }

我在处理在数据库中插入新实体时遇到了以下问题,该数据库将Guid作为主键-ef5,使用代码优先的方法

我知道有很多类似的主题,因为我在这个问题上花了几个小时,但我找不到这个问题的主题

例如,我的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; }
}
即使我执行常规添加,Guid键设置也不起作用:

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

    context.SaveChanges();
}
很明显,新的Guid值并没有从EF SQL生成器发送到SQL Server,所以问题出在EF中

因此,我删除了DatabaseGeneratedOption.Identity属性,这样就可以了,但是我失去了自动生成Id密钥的功能,这对我来说不起作用,因为这种情况非常罕见

我目前唯一的解决方案:

最后,我将覆盖DBContext的SaveChanges()方法,并修改所有需要添加状态的实体(我的想法来自:

///在changetracker中保存实体时的自定义处理
公共覆盖int SaveChanges()
{
//建议为适当的实体显式设置新Guid--http://msdn.microsoft.com/en-us/library/dd283139.aspx
foreach(ChangeTracker.Entries()中的var条目,其中(e=>e.State==EntityState.Added))
{
var t=entry.Entity.GetType();
if(t.GetProperty(“Id”)==null)
继续;
var info=t.GetProperty(“Id”).GetCustomAttributes(typeof(DatabaseGeneratedAttribute),true).Cast();
如果(!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);
}
}
返回base.SaveChanges();
}
与此相结合,应删除所有数据库生成选项。所有模型都有名为“Id”的主键,遵循命名约定的最佳实践主题之一

但这看起来不是很优雅的解决方法,因为我认为EF5应该能够处理这样的情况。如果“标识插入”处于启用状态,则它适用于Int标识


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

您可以将Id标记为虚拟财产。因此,在创建伪数据的项目中,可以使用重写Id的内部EntityRole,在这里可以删除DatabaseGenerateOption.Identity属性,或者在DatabaseGenerateOption.None上更改它。

由于它是GUID,所以实现这一点的简单方法是在类中使用一个构造函数,如

public EntityRole()
{
   Id = Guid.NewGuid();
}
并删除“数据库生成”选项或将其更改为“数据库生成”选项。无。

Visual Studio 2017,C#,EntityFramework v6.0允许您在创建时通过控制器传入自定义值,从而使用自定义值进行覆盖。它不需要在bc模型中定义,它已经在ApplicationUser中定义

private string DateGuid()
{

string pre=“丑陋的用户我们首先使用EF 5代码,只需在实体的键属性上设置
[Key]
属性。每次我们添加一个未设置键的实体,然后调用
context.SaveChanges()
,密钥是自动生成的,并且可以从实体对象中获得。主要区别在于我们的密钥是int而不是guid-不确定这是否重要。是的,对于int,它工作得很好,因为我认为它在数据库中很常见,SQL Server会为它生成新的Id基本上我一直在寻找其他解决方案but没有发现比我在问题中所展示的覆盖SaveChanges的方法更好的方法。它目前运行良好,如果我在Id中有值或没有值,那么我想现在就使用它。Thx无论如何是为了提示。对于少量的模型类,它看起来很好,但在我的问题中是模拟数据库生成的选项,而不是doi对于所有的DB模型,我们有大约50个,而且还在增长——对于每一个模型,我必须为Id创建一行构造函数。另一个问题是,当我们不在DB上下文中时,我们正在检查Id,以确定我们是否从DB中创建了这个模型,或者它只是创建的,还没有保存(例如在一个helper类中)。
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'
/// <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();
}
public EntityRole()
{
   Id = Guid.NewGuid();
}