Để tránh sử dụng Bảng phân cấp (TPH), tôi đã xem xét các ví dụ về cách thực hiện tốt nhất Lớp mỗi lớp bê tông (TPC) thừa kế trong mô hình cơ sở dữ liệu của tôi. Tôi đã xem qua số official documentation và this article.Thừa kế bảng trên mỗi loại bê tông (TPC) trong khuôn khổ thực thể 6 (EF6)
Dưới đây là một số lớp mô hình với một số thừa kế đơn giản.
public class BaseEntity
{
public BaseEntity()
{
ModifiedDateTime = DateTime.Now;
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime ModifiedDateTime { get; set; }
}
public class Person : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Business : BaseEntity
{
public string Name { get; set; }
public string Location { get; set; }
}
Cấu hình DbModelBuilder được sử dụng cho mỗi ví dụ trong cả hai bài viết.
modelBuilder.Entity<BaseEntity>()
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<Person>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Person");
});
modelBuilder.Entity<Business>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Business");
});
Ứng dụng chạy thành công nhưng khi tôi quay trở lại cơ sở dữ liệu, tôi tìm thấy ba (3) bảng thay vì hai (2) tôi dự kiến sẽ tìm thấy. Sau một chút thử nghiệm nó sẽ xuất hiện bảng "BaseEntity" được tạo ra nhưng không bao giờ được sử dụng. Mọi thứ dường như hoạt động tốt với ngoại lệ của cái bàn trống mồ côi này.
Tôi gây rối với cấu hình DbModelBuilder, cuối cùng xóa cấu hình "BaseEntity" cung cấp kết quả mong đợi; Hai (2) bảng, mỗi bảng có các thuộc tính chính xác và hoạt động chính xác.
Tôi làm một thử nghiệm cuối cùng, trích xuất tất cả cấu hình DbModelBuilder, chỉ bao gồm hai (2) thuộc tính DbSet cho "Người" và "Doanh nghiệp" và kiểm tra lại.
public DbSet<Person> People { get; set; }
public DbSet<Business> Businesses { get; set; }
Tôi ngạc nhiên khi dự án xây dựng, đi đến cơ sở dữ liệu, chỉ tạo hai bảng với tất cả các thuộc tính lớp bao gồm các bảng được thừa kế từ lớp "BaseEntity". Tôi có thể thực hiện các hoạt động CRUD mà không gặp vấn đề gì.
Sau khi chạy nhiều kiểm tra, tôi không thể tìm thấy bất kỳ vấn đề nào với thử nghiệm cuối cùng và tôi đã không thể tạo lại lỗi khóa trùng lặp cả hai bài báo được cảnh báo.
Các thay đổi đối với cơ sở dữ liệu đã được cam kết thành công, nhưng lỗi xảy ra khi cập nhật ngữ cảnh đối tượng. ObjectContext có thể là ở trạng thái không nhất quán. Thông báo ngoại lệ bên trong: AcceptChanges không thể tiếp tục vì các giá trị khóa của đối tượng xung đột với đối tượng khác trong ObjectStateManager. Đảm bảo rằng các giá trị khóa là duy nhất trước khi gọi AcceptChanges.
- Tôi tò mò tại sao các ví dụ sử dụng thuộc tính MapInheritedProperties; đây có phải là phương pháp lỗi thời không?
- Tại sao cả hai ví dụ nói để bao gồm các thuộc tính cấu hình cho "BaseEntity" nhưng bao gồm thuộc tính DbSet hoặc bất kỳ cấu hình DbModelBuilder nào cho lớp "BaseEntity" làm cho bảng không được sử dụng được tạo ra.
- Trong tham chiếu đến lỗi khóa duy nhất các bài báo được cảnh báo; Tôi không thể tái tạo lỗi và tôi đã thử nghiệm nhiều lần với khóa chính như là một int được tạo ra bởi cơ sở dữ liệu và một guid được tạo ra bởi cơ sở dữ liệu. Là thông tin về lỗi này cũng đã lỗi thời hoặc có một thử nghiệm tôi có thể chạy để tạo ra lỗi đã nói không?
Tôi nghĩ rằng nên có 3 bảng được tạo, mặc dù cơ sở có vẻ không sử dụng được. đó là một số loại khuyết điểm của TPC, bạn có thể mất một số lợi ích trong mã máy khách nhưng phải chịu một số dữ liệu thừa (không nên được tạo ngay cả trong khái niệm thiết kế cơ sở dữ liệu truyền thống). Tôi nghĩ rằng bạn có thể thử TPT thay vì trong khi bảng cơ sở chứa tất cả các cột phổ biến và nó sẽ không được coi là dư thừa nữa. – Hopeless
@Hopeless Lý do tôi không xem xét TPT, nhiều như tôi yêu khía cạnh thiết kế là OCD như tôi, là hiệu suất hit bạn lấy từ tất cả các tuyên bố tham gia cần thiết để kéo trở lại ngay cả dữ liệu hơi phức tạp. Đối với tuyên bố về 3 bảng, tôi đã nhìn thấy rất nhiều bài viết ngược lại nhưng một lần nữa không có gì tôi có thể làm việc một cách chính xác. Tôi tự hỏi nếu có một số bất lợi cho cách cuối cùng tôi thiết lập các mô hình; Tôi đã kết thúc với hai bảng, không có bảng rác, không có cột rác, không có vấn đề chính chính, nhưng tôi không thể tìm thấy ví dụ nào làm những gì tôi đã làm. – Nicholas
Đối với TPH, lớp BaseEntity phải trừu tượng. Tôi nghĩ rằng một mình chỉ nên tạo ra hai bảng DB cho các loại cụ thể. Tôi thực sự đã chạy vào ObjectContext này đang ở trong một lỗi nhà nước không phù hợp, và cách duy nhất tôi đã có thể sửa chữa nó là để làm cho trường Id trong BaseEntity loại Guid thay vì Int (mà có vẻ khá lãng phí). – blgrnboy