簡體   English   中英

EF,Code First - 如何在插入時設置自定義Guid標識值

[英]EF, Code First - How to set a custom Guid identity value on insert

在處理在Guid作為主鍵的數據庫中插入新實體時,我面臨以下問題 - 使用Code第一種方法的EF 5

我知道有很多類似的主題,因為我在這個問題上流浪了幾個小時,但我找不到這個問題的主題。

舉個例子,我的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。 所以,如果我在我的Configuration類中:

// 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鍵的自動生成,這對我來說不起作用,因為這是非常罕見的情況。

我現在唯一的解決方案:

我最終是覆蓋DBContext的SaveChanges()方法並修改所有要添加狀態的實體(我從這里接受了想法):

/// <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();
}

並刪除數據庫生成選項或將其更改為DatabaseGeneratedOption.None。

您可以將Id標記為虛擬財產。 因此,在您創建虛假數據的項目中,您可以使用覆蓋Id的內部EntityRole,在這里您可以刪除DatabaseGeneratedOption.Identity屬性或在DatabaseGeneratedOption.None上更改它。

Visual Studio 2017,C#,EntityFramework v6.0允許您通過控制器傳遞創建的值來覆蓋自定義值。 它不需要在模型bc中定義,它已在ApplicationUser中定義。

private string DateGuid()
    {
        string pre = "Ugly Users 😍🤔🤣😂-";
        return pre + Guid.NewGuid();
    }

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]    
public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { Id = DateGuid() };
            var result = await UserManager.CreateAsync(user, model.Password);
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM