2010-06-11 26 views
8

Tôi đang chuyển một ứng dụng hiện có từ LINQ sang SQL sang Entity Framework 4 (tạo mã mặc định).Khuôn khổ thực thể: Tự động cập nhật khóa ngoài khi đặt tham chiếu đối tượng mới

Một sự khác biệt tôi nhận thấy giữa hai là một thuộc tính khóa ngoài không được cập nhật khi đặt lại tham chiếu đối tượng. Bây giờ tôi cần phải quyết định làm thế nào để đối phó với điều này.

Ví dụ: giả sử bạn có hai loại thực thể, Công ty và Nhân viên. Một công ty có nhiều nhân viên.

Trong LINQ to SQL, thiết lập các công ty cũng đặt id ty:

Trong Entity Framework (và không sử dụng bất kỳ mẫu mã tùy biến) này không làm việc:

var company=new Company(ID=1); 
var employee=new Employee(); 
Debug.Assert(employee.CompanyID==0); 
employee.Company=company; 
Debug.Assert(employee.CompanyID==1); //Throws, since CompanyID was not updated! 

Tôi làm cách nào để EF hoạt động giống như LinqToSQL? Tôi đã nhìn vào mẫu T4 tạo mã mặc định, nhưng tôi không thể tìm ra cách thực hiện các thay đổi cần thiết. Nó có vẻ giống như một một lót nên làm các trick, nhưng tôi không thể tìm ra cách để có được tài sản ID cho một tham chiếu nhất định.

+0

Nếu bạn đã lưu thay đổi của bạn với những gì bạn mô tả, là trường ở giá trị đúng khi bạn chọn thực thể của bạn trở lại từ kho dữ liệu? –

+0

Vâng, tất nhiên rồi. Nhưng tôi có rất nhiều mã di sản mà vẫn phụ thuộc vào hành vi của L2S. –

Trả lời

4

Từ những gì tôi có thể thấy trong mẫu T4 mặc định, thuộc tính khóa ngoài của thực thể không được liên kết trực tiếp với tham chiếu thực thể được liên kết với khóa.

Có một cặp vợ chồng tiếp cận vấn đề của bạn về việc di chuyển từ LINQ to SQL sang EF4. Một trong số họ sẽ đăng ký sự kiện AssociationChanged của các hiệp hội của bạn để nó tự động cập nhật trường của bạn. Trong bối cảnh của bạn, một cách tiếp cận có thể là một cái gì đó như thế này:

// Extends Employee entity 
public partial class Employee 
{ 
    private void CompanyChanged(Object sender, CollectionChangeEventArgs e) 
    { 
     // Apply reactive changes; aka set CompanyID 
     // here 
    } 

    // Create a default constructor that registers your event handler 
    public Employee() 
    { 
     this.CompanyReference.AssociationChanged += CompanyChanged; 
    } 
} 

Cá nhân, nếu bạn muốn giới hạn việc duy trì cần thiết để duy trì loại này logic, tôi muốn đề nghị thay đổi mẫu T4 của bạn (hoặc thay đổi nó cho mình hoặc tìm một) để nó đặt CompanyId khi Company được thay đổi như được hiển thị trước đó.

Gil Fink đã viết một bản giới thiệu khá tốt cho các mẫu T4 với EF4 và bạn có thể tra cứu Scott Hanselman bao gồm một loạt các liên kết hữu ích và tài nguyên để làm việc với mẫu T4. Trên một lưu ý cuối cùng, trừ khi tôi bị nhầm lẫn, truy cập trực tiếp các khóa nước ngoài như là sự trợ giúp của một thực thể là cái gì đó mới từ EF3.5 đến 4. Trong 3.5, cách duy nhất bạn có thể truy cập nó là thông qua thực thể liên quan (Employee.Company.CompanyID).). Tôi tin rằng tính năng này đã được thêm vào trong EF4 để bạn không phải tải các liên kết (sử dụng "include") để lấy khóa ngoài khi chọn từ kho dữ liệu.

Có lẽ EF thực hiện điều này sẽ là, nếu bạn có liên kết, hãy trải qua liên kết để nhận ID, trước tiên và quan trọng nhất. Nhưng đó chỉ là suy đoán khi tôi không có dấu ngoặc kép để sao lưu nó.

[EDIT 2010/06/16]: Sau một readthrough và phân tích các yếu tố edmx xml nhanh chóng, tôi tìm thấy một gọi ReferentialConstraint mà dường như có chứa các lĩnh vực then chốt nước ngoài tham gia FK_Relation specfic.

Heres đoạn mã để sửa đổi bên trong mẫu mặc định T4 edmx, phần Viết Thuộc tính điều hướng. (Template_RegionNavigationProperties), xung quanh dòng 388 của mẫu chưa được sửa đổi.Hãy cố gắng bỏ qua định dạng khủng khiếp ...

<#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForProperty(navProperty)#> <#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#> <#=code.Escape(navProperty)#> 
    { 
     <#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get 
     { 
      return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value; 
     } 
     <#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set 
     { 
      // edit begins here 
      if(value != null) 
      { 
       // Automatically sets the foreign key attributes according to linked entity 

<# 
      AssociationType association = GetSourceSchemaTypes<AssociationType>().FirstOrDefault(_ => _.FullName == navProperty.RelationshipType.FullName); 
      foreach(var cons in association.ReferentialConstraints) 
      { 
       foreach(var metadataProperty in cons.FromProperties) 
       { 
#> 
       this.<#=metadataProperty.Name#> = value.<#=metadataProperty.Name#>; 
       //this._<#=metadataProperty.Name#> = value._<#=metadataProperty.Name#>; // use private field to bypass the OnChanged events, property validation and the likes.. 

<# 
       } 
      } 
#> 
      } 
      else 
      { 
       // what usually happens in Linq-to-SQL when an association is set to null 
       // here 
      } 
      // edit ends here 

      ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value = value; 
     } 
    } 

Tôi đã thử nghiệm kỹ lưỡng, nhưng có một số xác định và thiếu sót đó. Có lẽ nó có thể cung cấp cho bạn một mẹo hướng tới một giải pháp bất kể.

+0

Cảm ơn bạn đã trả lời. Thêm một trình xử lý sự kiện cho mọi liên kết sẽ hoạt động, nhưng sẽ có rất nhiều (errorprone) hoạt động trên mô hình hiện tại cộng với một khả năng tuyệt vời mà tôi quên làm điều này sau. Vì vậy, cách tiếp cận T4 thực sự có vẻ là con đường để đi. Như tôi đã nói, tôi đã xem mẫu T4. Nói chung tôi biết làm thế nào T4 hoạt động, tôi đã có một chút công bằng kinh nghiệm với nó, nhưng tôi không thể tìm ra cách để có được tài sản ID cho một tham chiếu nhất định từ siêu dữ liệu EF. Tôi đã từ bỏ sau một vài giờ và bắt đầu đăng bài này ... –

+0

Thật vậy, nó xuất hiện không có liên kết giữa các tài sản FK và tham chiếu FK, thậm chí không phải là một thuộc tính tùy chỉnh. Bạn có tuân theo bất kỳ loại quy ước đặt tên nào cho khóa ngoại của bạn không đổi trên DB quan hệ của bạn không? –

+0

Thường thì có, do đó, phản ánh có thể sẽ hoạt động. Nếu không có tùy chọn khác (tôi đã hy vọng tôi đã bỏ lỡ một số liên kết giữa tham chiếu và id), tôi sẽ cố gắng sử dụng phương pháp này để thay thế. –

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