2012-12-06 29 views
10

Tôi đang gặp vấn đề sau khi xử lý việc chèn đối tượng mới trong DB có Hướng dẫn làm khóa chính - EF 5 với Mã số trước tiếp cận.EF, Mã đầu tiên - Cách đặt giá trị nhận dạng Guid tùy chỉnh khi chèn

Tôi biết có rất nhiều chủ đề tương tự như tôi đã lưu hành hàng giờ cho vấn đề này, nhưng tôi không thể tìm thấy chủ đề với vấn đề này.

Như một ví dụ, lớp POCO của tôi là:

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 và Tên chỉ là dữ liệu văn bản, đó là có thể chỉnh sửa trong bảng quản trị, vì vậy don `t xem xét những tên trường.

Khi thêm đối tượng mới, tôi không chỉ định giá trị khóa chính. Cho đến nay rất tốt, tất cả các công trình tốt ở đây. Là trường khóa chính yêu cầu giá trị và có tự động tạo các giá trị, không phải lúc nào cũng chỉ định Id, nhưng nếu tôi đặt giá trị, nó sẽ được giữ lại (nếu tính năng chèn danh tính được bật).

Nhưng trong một số trường hợp, tôi muốn chỉ định giá trị khóa chính, ví dụ như cho việc tạo chuỗi ban đầu của DB của tôi với các giá trị. Tôi cần nó để xử lý sau - cho phép chỉ cần nói rằng tôi cần có Guid cụ thể để có mặt ở đó. Vì vậy, nếu tôi có trong lớp Cấu hình của tôi:

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

Bối cảnh chính Guid đi không hoạt động ngay cả khi tôi làm một add thường xuyên:

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

    context.SaveChanges(); 
} 

gì tôi có trong SQL Server dấu vết là:

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' 

Đây rõ ràng là giá trị Guid mới không được gửi từ bộ tạo SQL EF đến máy chủ SQL, do đó, vấn đề nằm trong EF.

Vì vậy, tôi đã xóa thuộc tính DatabaseGeneratedOption.Identity, sau đó được, nhưng tôi mất tự động tạo khóa Id, không hoạt động đối với tôi vì trường hợp này rất hiếm.

Giải pháp duy nhất từ ​​tôi cho bây giờ:

tôi đã kết thúc là để ghi đè lên SaveChanges() phương pháp của DBContext và sửa đổi tất cả các thực thể có nhà nước sẽ được bổ sung (Tôi đã lấy ý tưởng từ 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(); 
} 

kết hợp với điều này, tất cả DatabaseGeneratedOption cần được loại bỏ. Tất cả các mô hình đều có các khóa chính có tên là "Id", theo một trong những chủ đề thực hành tốt nhất cho quy ước đặt tên.

Nhưng điều này không có vẻ rất thanh lịch workaronud, bởi vì tôi thnk EF5 sẽ có thể xử lý các trường hợp như vậy. Nó hoạt động đối với nhận dạng Int nếu tính năng chèn danh tính được bật.

Vậy ai đó có ý tưởng làm thế nào để đạt được giải pháp tốt hơn về vấn đề này?

+0

Chúng tôi sử dụng EF 5 mã đầu tiên và chỉ cần đặt thuộc tính '[Key]' trên các thuộc tính chính của các thực thể của chúng tôi. Mỗi khi chúng ta thêm một thực thể mà khóa không được thiết lập, và sau đó gọi 'context.SaveChanges()', khóa được tạo tự động và có sẵn cho chúng ta từ đối tượng thực thể. Điểm khác biệt chính là chìa khóa của chúng tôi là ints thay vì Guids - không chắc liệu điều đó có quan trọng không. –

+0

Có, với ints nó làm việc tốt, vì tôi nghĩ rằng nó là requential trong DB và SQL Server tạo ra Id mới cho nó –

Trả lời

2

Bạn có thể đánh dấu Id là thuộc tính ảo. Vì vậy, trong bạn dự án nơi bạn tạo dữ liệu giả, bạn có thể có EntityRole nội bộ với Id overriden và ở đây bạn có thể loại bỏ DatabaseGeneratedOption.Nhận dạng thuộc tính hoặc thay đổi nó trên DatabaseGeneratedOption.None.

+0

Về cơ bản tôi đã được tìm kiếm các giải pháp khác nhưng không tìm thấy tốt hơn so với phương pháp ghi đè SaveChanges như Tôi đã cho thấy trong câu hỏi. Nó hoạt động tốt cho bây giờ và không có vấn đề về điều đó nếu tôi có giá trị trong Id hay không vì vậy tôi nghĩ rằng để đi với nó cho bây giờ. Thx dù sao cho gợi ý. –

3

Cách đơn giản để bạn có thể làm điều này vì nó là một GUID là phải có một constructor trong lớp học của bạn như

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

và loại bỏ Cơ sở dữ liệu tùy chọn tạo hoặc thay đổi nó để DatabaseGeneratedOption.None.

+0

Có vẻ tốt cho số lượng nhỏ các lớp mô hình, nhưng trong vấn đề của tôi là để mô phỏng các tùy chọn tạo cơ sở dữ liệu và không làm điều này cho tất cả các mô hình DB. Chúng tôi có khoảng 50 và đang phát triển - cho mỗi người trong số họ tôi phải tạo ra các nhà thầu với 1 dòng cho Id. Một vấn đề khác là chúng ta đang kiểm tra Id khi chúng ta không phải là bối cảnh DB để xác định xem chúng ta có mô hình này từ DB hay nó chỉ được tạo và vẫn không được lưu (ví dụ trong lớp trợ giúp). –

Các vấn đề liên quan