2010-07-02 30 views
8

Hãy giúp EF thiết kế cơ sở dữ liệu của mình. Tôi có một số công ty sản xuất một số sản phẩm, vì vậy có mối quan hệ nhiều-nhiều giữa các công ty và sản phẩm. Tôi có một bảng trung gian, Company_Product, có liên quan đến chúng.Khuôn khổ thực thể nhiều câu hỏi với nhiều câu hỏi

Mỗi kết hợp công ty/sản phẩm có SKU duy nhất. Ví dụ: vật dụng Acme có SKU 123, nhưng các vật dụng Omega có SKU 456. Tôi đã thêm SKU làm trường trong bảng trung gian Company_Product.

EF đã tạo mô hình có mối quan hệ 1: * giữa bảng công ty và bảng Company_Product và mối quan hệ 1: * giữa bảng sản phẩm và bảng Company_Product. Tôi thực sự muốn có mối quan hệ giữa công ty và sản phẩm : giữa công ty và sản phẩm. Nhưng, quan trọng nhất, không có cách nào để truy cập SKU trực tiếp từ mô hình.

Tôi có cần phải đặt SKU trong bảng riêng của mình và viết một kết nối hoặc có cách nào tốt hơn không?

+0

Mọi thứ đều ổn… Bạn phải có 3 thực thể trong mô hình của mình: Công ty, Sản phẩm và Công ty_Sản phẩm. "không có cách nào để truy cập SKU trực tiếp từ mô hình" bạn đã thử ctx.Company_Products.First(). SKU? –

Trả lời

33

tôi chỉ thử nghiệm điều này trong một dự án VS2010 mới (EFv4) để chắc chắn, và đây là những gì tôi thấy:

Khi bảng kết của bạn ở giữa (Company_Product) có CHỈ các phím 2 xa lạ đối với các bảng khác (CompanyID và ProductID), sau đó thêm tất cả 3 bảng vào trình thiết kế kết thúc mô hình hóa mối quan hệ nhiều đến nhiều. Nó thậm chí không tạo ra một lớp cho bảng Company_Product. Mỗi Công ty có một bộ sưu tập Sản phẩm và mỗi Sản phẩm có một bộ sưu tập Công ty. Tuy nhiên, nếu bảng kết hợp của bạn (Company_Product) có các trường khác (chẳng hạn như SKU, khóa chính của chính nó hoặc các trường mô tả khác như ngày tháng, mô tả, v.v.) thì nhà mô hình EF sẽ tạo một lớp riêng biệt và làm những gì bạn đã thấy.

Có lớp ở giữa với mối quan hệ 1: * cho Công ty và Sản phẩm không phải là điều xấu và bạn vẫn có thể nhận được dữ liệu bạn muốn với một số truy vấn dễ dàng.

// Get all products for Company with ID = 1 
var q = 
    from compProd in context.Company_Product 
    where compProd.CompanyID == 1 
    select compProd.Product; 

Đúng, không dễ dàng điều hướng các mối quan hệ của mô hình, ví dụ, nhưng đó là lớp dữ liệu. Đóng gói các truy vấn nhận dữ liệu bạn muốn. Nếu bạn thực sự muốn loại bỏ lớp Company_Product ở giữa đó, và có nhiều-nhiều đại diện trực tiếp trong mô hình lớp, thì bạn sẽ phải loại bỏ bảng Company_Product chỉ chứa 2 khóa ngoài và loại bỏ của SKU.

Thực ra, tôi không nên nói rằng bạn phải làm điều đó ... bạn có thể thực hiện một số chỉnh sửa trong nhà thiết kế và thiết lập theo cách này. Tôi sẽ thử và báo cáo lại.

CẬP NHẬT

Giữ SKU trong bảng Company_Product (có nghĩa là mô hình EF của tôi có 3 lớp, không phải 2, nó tạo ra lớp Company_Payload, với tỉ lệ 1: * vào 2 bảng khác), tôi đã cố gắng để thêm liên kết trực tiếp giữa Công ty và Sản phẩm.Các bước Tôi đi theo là:

  • Nhấp chuột phải vào lớp Công ty trong thiết kế
  • Thêm> Hiệp hội
  • Set "End" ở bên trái là Công ty (nó nên đã)
  • Set "Kết thúc" ở bên phải để sản phẩm
  • Thay đổi cả bội để "* (Nhiều)" "Sản phẩm"
  • các thuộc tính định hướng nên được đặt tên và "công ty"
  • Hit OK.
  • Right Click về mối tương quan trong mô hình> bấm vào nút "Bảng Mapping"
  • Dưới "Thêm một bảng hoặc xem" chọn "Company_Product"
  • Bản đồ Công ty -> ID (ở bên trái) để CompanyID (bên phải)
  • Sản phẩm bản đồ -> ID (bên trái) đến ProductID (ở bên phải)

Nhưng, nó không hoạt động. Nó đưa ra lỗi này: Lỗi 3025: Sự cố trong phân đoạn ánh xạ bắt đầu từ dòng 175: Phải chỉ định ánh xạ cho tất cả các thuộc tính quan trọng (Company_Product.SKU) của bảng Company_Product.

Vì vậy, liên kết cụ thể đó không hợp lệ, vì nó sử dụng Company_Product làm bảng, nhưng không ánh xạ trường SKU thành bất kỳ thứ gì.

Ngoài ra, trong khi tôi đang nghiên cứu điều này, tôi đã xem qua phần "Thực hành tốt nhất" này từ cuốn sách Entity Framework 4.0 Recipies (lưu ý rằng đối với bảng kết hợp có thêm trường, ngoài 2 FK, chúng tham chiếu đến các trường bổ sung là "trọng tải". Trong trường hợp của bạn, SKU là trọng tải trong Company_Product).

Best Practice

Unfortunately, a project that starts out with several, payload-free, many-to-many relationships often ends up with several, payload-rich, many-to-many relationships. Refactoring a model, especially late in the development cycle, to accommodate payloads in the many-to-many relationships can be tedious. Not only are additional entities introduced, but the queries and navigation patterns through the relationships change as well. Some developers argue that every many-to-many relationship should start off with some payload, typically a synthetic key, so the inevitable addition of more payload has significantly less impact on the project.

So here's the best practice. If you have a payload-free, many-to-many relationship and you think there is some chance that it may change over time to include a payload, start with an extra identity column in the link table. When you import the tables into your model, you will get two one-to-many relationships, which means the code you write and the model you have will be ready for any number of additional payload columns that come along as the project matures. The cost of an additional integer identity column is usually a pretty small price to pay to keep the model more flexible.

(Từ Chương 2. Entity Data Modeling Fundamentals, 2.4. Mô hình hóa một mối quan hệ Nhiều-to-Nhiều với Payload)

Âm thanh như lời khuyên tốt. Đặc biệt là vì bạn đã có một trọng tải (SKU).

+0

Chạy vào cùng một vấn đề chính xác, câu trả lời hay. –

2

Tôi chỉ muốn thêm dòng sau vào Samuel của câu trả lời:

Nếu bạn muốn truy vấn trực tiếp từ một phía của một nhiều-nhiều mối quan hệ (với tải trọng) để người kia, bạn có thể sử dụng sau đây mã (sử dụng ví dụ tương tự):

Company c = context.Companies.First(); 
IQueryable<Product> products = c.Company_Products.Select(cp => cp.Product); 

biến products sau đó sẽ là tất cả Product hồ sơ liên quan đến việc kỷ lục Company c. Nếu bạn muốn bao gồm các SKU cho mỗi sản phẩm, bạn có thể sử dụng một lớp vô danh như vậy:

var productsWithSKU = c.Company_Products.Select(cp => new { 
    ProductID = cp.Product.ID, 
    Name = cp.Product.Name, 
    Price = cp.Product.Price, 
    SKU = cp.SKU 
}); 
foreach (var 

Bạn có thể đóng gói truy vấn đầu tiên trong một thuộc tính chỉ đọc vì đơn giản như vậy:

public partial class Company 
{ 
    public property IQueryable<Product> Products 
    { 
    get { return Company_Products.Select(cp => cp.Product); } 
    } 
} 

Bạn không thể làm điều đó với truy vấn bao gồm SKU vì bạn không thể trả về các loại ẩn danh. Bạn sẽ phải có một lớp xác định, thường sẽ được thực hiện bằng cách thêm thuộc tính không được ánh xạ vào lớp Product hoặc tạo một lớp khác kế thừa từ Product có thể thêm thuộc tính SKU.Tuy nhiên, nếu bạn sử dụng một lớp được thừa kế, bạn sẽ không thể thực hiện các thay đổi đối với nó và nó được quản lý bởi EF - nó sẽ chỉ hữu ích cho mục đích hiển thị.

Chúc mừng. :)