2010-09-04 29 views
6

Tôi làm theo bằng ví dụ khuôn khổ tổ chức:nhận dạng cột trong EF 4

http://msdn.microsoft.com/en-us/library/bb399182.aspx

và tôi có vấn đề với nhận dạng cột.

Dưới đây là một phần của quy tắc ứng tạo ra cơ sở dữ liệu:

CREATE TABLE [dbo].[Person](
    [PersonID] [int] IDENTITY(1,1) NOT NULL, 
    [LastName] [nvarchar](50) NOT NULL, 
    [FirstName] [nvarchar](50) NOT NULL, 
    [HireDate] [datetime] NULL, 
    [EnrollmentDate] [datetime] NULL, 
CONSTRAINT [PK_School.Student] PRIMARY KEY CLUSTERED 
(
    [PersonID] ASC 
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY] 
) ON [PRIMARY] 
END 
GO 

Trong VS 2010 tôi xây dựng .edmx và ở mô hình tôi thấy rằng Người StoreGeneratedPattern được thiết lập để nhận dạng.

Nhưng khi tôi muốn tạo Person, bởi: alt text

Tại sao tôi phải đưa id, nếu cột này là autoincrement?

EDITŁ

Tôi nghĩ rằng tôi tìm thấy cách để giải quyết vấn đề của tôi bởi:

var schoolContext = new SchoolEntities(); 

      schoolContext.AddToPeople(new Person() { LastName = "Gates", FirstName = "Bil" }); 

      schoolContext.SaveChanges(); 

vì nó bổ sung Bill cho người, nhưng ... vì PersonID không nullable, và nó chèn ông với id 0. Khi tôi cố gắng thêm một người khác theo cùng một cách tất nhiên tôi nhận được lỗi về khóa chính :)

Vì vậy, vẫn không có gì ...

Bất kỳ ý tưởng?

Trả lời

6

Tôi không thể cho bạn biết tại sao nhóm EF chọn làm theo cách này - phỏng đoán duy nhất của tôi là việc tạo mã tạo phương thức CreatePerson không kiểm tra xem ID có tự động hay không và chỉ tạo một phương thức sẽ hoạt động trong bất kỳ trường hợp nào - cho dù ID là tự động hay không.

Nếu điều này thực sự làm phiền bạn, bạn cũng có thể được hưởng lợi từ thực tế là các thực thể lớp tạo Person được định nghĩa là một partial class, vì vậy bạn có thể mở rộng nó một cách dễ dàng. Tạo tệp lớp mới có tên là v.d. PersonEx.cs và mở rộng mà partial class:

public partial class Person 
{ 
    public static Person CreatePerson(string lastName, string firstName) 
    { 
     return CreatePerson(-1, lastName, firstName); 
    } 
} 

Bây giờ, bạn có thể dễ dàng tạo ra Person thực thể của bạn mà không chỉ định một ID, và thêm chúng vào dữ liệu của bạn:

using(SchoolEntities context = new SchoolEntities()) 
{ 
    Person newPerson = Person.CreatePerson("Gates", "Bill"); 
    context.AddToPeople(newPerson); 

    context.SaveChanges(); 

    int newID = newPerson.PersonID; 
} 

Nó không phải là một giải pháp hoàn hảo - nhưng nó nên làm việc tốt (ít nhất là nó cho tôi).

+0

Cảm ơn bạn Marc! Đó là lần sau bạn tiết kiệm cho tôi rất nhiều thời gian – user278618

+0

Mẫu đẹp nhưng tôi nghĩ bạn sẽ an toàn hơn bằng cách sử dụng mặc định 0 cho id .. -1 sẽ không kiểm tra giá trị mặc định và người ta có thể đoán bạn sẽ không thiết kế bảng có nhận dạng bắt đầu từ số không. –

+0

@daveL: số âm làm việc tốt cho tôi .... –

7

IMO Id là cần thiết ngay cả khi được tạo. Giả sử bạn đang sử dụng tổ hợp khóa ngoài (hành vi khác với liên kết độc lập). Nó có nghĩa là các thực thể con liên quan đang sử dụng khóa chính của thực thể cha để xây dựng quan hệ. Bây giờ giả sử rằng bạn đang thêm nhiều thực thể cha với các thực thể liên quan trong một đơn vị công việc. Bạn phải xác định duy nhất (tạm thời) Id cho mỗi thực thể cha mẹ nếu không bạn sẽ không bao giờ cấu hình đồ thị đối tượng của bạn. Vì vậy, trình tạo mã có thể làm cho điều này là mặc định.

Edit:

Tôi ngạc nhiên mà tôi đã được downvoted cho câu trả lời dựa trên những sự kiện chính xác.Vì vậy, hãy để tôi làm rõ câu trả lời của tôi:

Có hai loại quan hệ có sẵn trong EF 4.0. Hiệp hội độc lập và hiệp hội quan trọng nước ngoài. Sự khác biệt là sau này thêm thuộc tính khóa ngoại vào các thực thể. Điều này cho phép bạn làm việc với các mối quan hệ giống như trong cơ sở dữ liệu - đơn giản bằng cách thiết lập các khóa. Bạn có thể đọc về các sự khác biệt này trong MSDN.

Bây giờ, hãy giả sử ví dụ đơn giản. Tôi có mô hình EDMX đơn giản với MyContext. Mô hình bao gồm hai thực thể Order và OrderLine. Khi tôi thêm các bảng Order và OrderLines vào mô hình, tôi đã thêm vào các cột khóa ngoài trong mô hình vì vậy tôi đang sử dụng các tổ hợp khóa ngoài thay vì các liên kết độc lập.

Đơn đặt hàng đã lưu trữ Id được tạo dưới dạng khóa và CustomerName làm tài sản. Dòng đơn đặt hàng đã tạo ID cửa hàng làm khóa, ProductTitle làm thuộc tính và OrderId làm khóa ngoại. Tôi muốn thêm hai đơn đặt hàng vào một đơn vị công việc:

using (var context = new MyContext()) 
{ 
    var ox = Order.CreateOrder(0, "CustomerX"); 
    var oy = Order.CreateOrder(0, "CustomerY"); 

    // Building relationship in the same way as in database 
    var olx = OrderLine.CreateOrderLine(0, ox.Id, "ProductX"); 
    var oly = OrderLine.CreateOrderLine(0, oy.Id, "ProductY"); 

    context.Orders.AddObject(ox); 
    context.Orders.AddObject(oy); 
    context.OrderLines.AddObject(olx); 
    context.OrderLines.AddObject(oly); 
    context.SaveChanges(); // UpdateException: Unable determine principal end of Model.FK_OrderLine_Order relationship. Multiple added entities have the same primary key. 
} 

Lỗi tôi đã làm trong mã của tôi là đặt Id của cả hai đơn đặt hàng mới thành 0. Ngay cả khi Id này tạm thời, nó vẫn phải là duy nhất nếu bạn muốn sử dụng nó cho các phím nước ngoài. Có thể bạn có thể hỏi tại thời điểm này bối cảnh không tự xử lý Id? Đơn giản vì nó không thể. Bối cảnh biết rằng Id là tạm thời và sẽ được tạo lại trong cửa hàng nhưng ngữ cảnh không biết chi tiết về cấu hình cửa hàng. Khi bạn thiết lập danh tính trong cơ sở dữ liệu, bạn cũng thiết lập hạt giống và gia tăng. Hai giá trị này không được biết đến trong ngữ cảnh, vì vậy ngữ cảnh không thể lấy được mã định danh tạm thời hợp lệ mà chưa được cửa hàng sử dụng. Giả sử bối cảnh đó tạo sai một số Id tạm thời và sau đó bạn tải thực thể đã sử dụng vấn đề Id = này.

Nếu tôi chỉ cập nhật mã của mình để sử dụng Id tạm thời duy nhất (Tôi biết cách cửa hàng được định cấu hình) nó sẽ hoạt động. Đó là IMO một lý do tại sao tôi cần phải cung cấp các phương thức Id để tạo tạm thời.

+0

Tôi không nghĩ rằng sẽ có một vấn đề nếu bạn có một số đối tượng cha với 'ID = -1' với các đối tượng con. Nó sẽ chỉ chèn phụ huynh cho cha mẹ, và sử dụng '@@ IDENTITY' để liên kết các child. Thuộc tính 'Id' không được sử dụng để tạo biểu đồ đối tượng. –

+0

Những gì bạn mô tả hoạt động cho hiệp hội độc lập. Tôi mô tả hiệp hội quan trọng nước ngoài. –

2

Bạn sẽ có thể tùy chỉnh mẫu t4 tạo lớp học của bạn để xóa thuộc tính khỏi phương thức gốc. Xem Danny Simmons' blog post để biết thông tin về cách tạo t4. Tôi đã không thử nghiệm phương pháp nhà máy kết quả, nhưng tôi không thể thấy lý do tại sao nó sẽ không hoạt động.

Sau đó, thay đổi phương pháp này:

bool IncludePropertyInFactoryMethod(StructuralType factoryType, EdmProperty edmProperty) 
{ 
    if (edmProperty.Nullable) 
    { 
     return false; 
    } 

    if (edmProperty.DefaultValue != null) 
    { 
     return false; 
    } 

    if ((Accessibility.ForReadOnlyProperty(edmProperty) != "public" && Accessibility.ForWriteOnlyProperty(edmProperty) != "public") || 
     (factoryType != edmProperty.DeclaringType && Accessibility.ForWriteOnlyProperty(edmProperty) == "private") 
     ) 
    { 
     // There is no public part to the property. 
     return false; 
    } 

    /********* 
    * This was added: 
    */ 

    var identity = edmProperty.TypeUsage.Facets 
     .Where(f => f.Name == "StoreGeneratedPattern").FirstOrDefault(); 

    if (identity != null && identity.Value.ToString() == "Identity") 
    { 
     // property is "Identity" generated, so skip from the factory method. 
     return false; 
    } 

    /********* 
    * end of the custom code 
    */ 

    return true; 
} 
+2

điều này sẽ làm việc cho StorageModel. Nếu bạn muốn sử dụng mô hình Khái niệm, bạn sẽ cần phải sử dụng MetadataProperties. tức là: property.MetadataProperties.TryGetValue (annotationNamespace + ": StoreGeneratedPattern", false, out storeGeneratedPatternProperty); –

+0

@SimonFrancesco, bạn có thể vui lòng giải thích thêm về cách thực hiện việc này không, chú thíchNamespace là gì? – Shimmy

+0

@Shimmy, Trong mẫu T4 của bạn, bạn có thể làm một cái gì đó như: 'String annotationNamespace =" http://schemas.microsoft.com/ado/2009/02/edm/annotation "; \t \t \t MetadataProperty storeGeneratedPatternProperty = null; \t \t \t thuộc tính.MetadataProperties.TryGetValue (chú thíchNamespace + ": StoreGeneratedPattern", false, out storeGeneratedPatternProperty); 'Nếu bạn cần một lời giải thích dài hơn sẽ được hạnh phúc để đăng câu trả lời :) –

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