2010-09-01 44 views

Trả lời

11

Bạn chỉ đang tìm kiếm nội dung như thế này?

public class User 
{ 
    public int Id { get; set; } 
    public string Username { get; set; } 
    public Profile Profile { get; set; } 
    public int ProfileId { get; set; } 
} 

public class Profile 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string PostalCode { get; set; } 
    // etc... 
} 

public class UserMapping : EntityConfiguration<User> 
{ 
    public UserMapping() 
    { 
     this.HasKey(u => u.Id); 
     this.Property(u => u.Username).HasMaxLength(32); 

     // User has ONE profile. 
     this.HasRequired(u => u.Profile); 
    } 
} 

public class ProfileMapping : EntityConfiguration<Profile> 
{ 
    public ProfileMapping() 
    { 
     this.HasKey(p => p.Id); 
     this.Property(p => p.FirstName).HasMaxLength(32); 
     this.Property(p => p.LastName).HasMaxLength(32); 
     this.Property(p => p.PostalCode).HasMaxLength(6); 
    } 
} 

EDIT: Vâng tôi không có VS trước mặt tôi nhưng bạn cần phải thêm dòng sau trong UserMapping thay vì hiện tại HasRequired và cũng thêm một tài sản ProfileId (thay vì Profile_Id mà bạn đã thêm):

this.HasRequired(u => u.Profile).HasConstraint((u, p) => u.ProfileId == p.Id); 

Tôi hiện không nghĩ rằng có cách nào khác, nhưng tôi chắc chắn nó sẽ thay đổi vì chúng tôi chỉ có trong CTP4. Sẽ tốt hơn nếu tôi có thể nói:

this.HasRequired(u => u.Profile).WithSingle().Map(
    new StoreForeignKeyName("ProfileId")); 

Bằng cách này, tôi sẽ không bao gồm tài sản ProfileId. Có lẽ có một cách xung quanh điều này hiện tại và nó vẫn còn vào sáng sớm để tôi nghĩ :).

Cũng nhớ gọi số .Include("Profile") nếu bạn muốn bao gồm "thuộc tính điều hướng".

+0

Tính năng này có phù hợp với bạn không? Tôi không thể làm cho nó hoạt động được. Tôi không tự động tạo cơ sở dữ liệu vì tôi có các bảng hiện có. Bảng hồ sơ của tôi có Id là PK và FK (vì mối quan hệ là 1: 1). Tôi lấy nó rằng điều này cũng giống như bạn. Nếu tôi thử và chạy mã của bạn, tôi gặp lỗi: Tên cột không hợp lệ 'Profile_Id'. Nếu tôi thêm cột đó vào Người dùng (không phải là tôi muốn nó ở đó), người dùng được trả về nhưng hồ sơ là rỗng. Các sql tạo ra là:. CHỌN [Extent1] [Id] AS [Id], [Extent1] [Tên] AS [Tên], [Extent1] [PROFILE_ID] AS [PROFILE_ID] FROM [dbo.. ]. [Người dùng] AS [Extent1] Bất kỳ ý tưởng nào? –

+0

hmm. Ngày kiểm tra thứ hai, có vẻ như điều này hoạt động tốt trên sqlce4, nhưng không sql server 2010 trừ khi tôi đang thiếu một cái gì đó. –

+1

@ zaph0d - Nếu bạn muốn truy cập thuộc tính là "một thực thể khác", bạn cần phải "bao gồm" nó. Cách để làm điều đó sẽ là 'context.Users.Include (" Profile ")'. Tiểu sử là một "thuộc tính điều hướng" sẽ yêu cầu JOIN trong SQL. Tôi đã chỉnh sửa bài đăng của mình bằng một chút thông tin mà tôi quên cho tiểu sử. – TheCloudlessSky

1
public class User 
{ 
    public int Id { get; set; } 
    public string Username { get; set; } 

    public virtual Profile Profile { get; set; } 
} 

public class Profile 
{ 
    public int Id { get; set; } 

    public int UserID { get; set; } 

    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string PostalCode { get; set; } 
} 

Thêm cấu hình ảo và UserID và tôi nghĩ rằng sẽ giúp bạn ở đó.

+2

Chẳng phải đó là mối quan hệ một đến nhiều sao? Câu hỏi là khoảng 1: 1. – saille

+0

Không, không. 1: 1 Người dùng có 1 Tiểu sử trong ví dụ này ... Nếu tôi không hiểu sai điều gì đó hoàn toàn. – BjarkeCK

22

Ba phương pháp:

A) Khai báo cả hai lớp có thuộc tính điều hướng với nhau. Đánh dấu một trong các bảng (bảng phụ thuộc) bằng thuộc tính ForeignKey trên Khóa chính của nó. EF suy luận 1-to-1 từ này:.

public class AppUser 
{ 
    public int Id { get; set; } 

    public string Username { get; set; } 

    public OpenIdInfo OpenIdInfo { get; set; } 
} 

​public class OpenIdInfo 
{ 
    [ForeignKey("AppUser")] 
    public int Id { get; set; } 

    public string OpenId { get; set; } 

    public AppUser AppUser { get; set; } 
} 

http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx

Tôi không sử dụng virtual và bạn không nên hoặc *

B) Khai báo một hệ thống phân cấp thừa kế với cả hai tên bảng được khai báo rõ ràng, dẫn đến Bảng mỗi loại và Khóa chính được chia sẻ.

using System.ComponentModel.DataAnnotations; 

[Table("AppUser")] 
public class AppUser 
{ 
    public int Id { get; set; } 

    public string Username { get; set; } 

    public OpenIdInfo OpenIdInfo { get; set; } 
} 

[Table("AdminUser")]  
public class AdminUser : AppUser 
{ 
    public bool SuperAdmin { get; set; } 
} 

Bạn sẽ nhận được 2 bảng: Một dành cho Người dùng ứng dụng, một cho Người dùng quản trị viên. AdminUser là 1: 1 với AppUser và là Dependent - có nghĩa là bạn có thể xóa AdminUser, nhưng nếu bạn xóa một AppUser khi AdminUser vẫn trỏ vào nó, bạn sẽ nhận được một lỗi vi phạm Constraint.

C) Có 2 phương pháp nửa chặng đường làm one-to-one trong EF:

Entity-Splitting, nơi bạn có một lớp duy nhất, nhưng nó được lưu trữ trong một bảng tiểu học, và 1 hoặc nhiều các bảng liên quan một-một.

Table-Splitting, nơi một cây đối tượng làm phẳng thành một bảng. Ví dụ một lớp có thuộc tính Address sẽ có các cột cho đối tượng Address, như Address_City, được san phẳng thành một bảng đơn.

* Bạn có thể bao gồm ảo trên bất kỳ Tài sản hoặc Bộ sưu tập EF nào if you want to lazy-load them. Điều này có thể dẫn đến các vòng lặp vô hạn hoặc tải toàn bộ DB nếu bạn truyền một đối tượng có các thuộc tính lười biếng, ví dụ, trình chuyển đổi MVC JSON hoặc bất kỳ thứ gì khác đi vào hệ thống phân cấp đối tượng. Lazy-Loading luôn được thực hiện Đồng bộ, chặn luồng và không cần thông báo. Tóm lại, danh sách các cách bạn có thể đóng băng mã, ứng dụng hoặc máy chủ của bạn với nó là dài. Tránh sử dụng ảo trên các lớp EF. Có, có rất nhiều mẫu mã trên internet sử dụng nó. Không, bạn vẫn không nên sử dụng nó.

+0

lý do tại sao không sử dụng từ khóa 'ảo' – AminM

+0

@AminM Xem lưu ý ở phần cuối về tải chậm và ảo. –

1

Lấy ví dụ về các thực thể Sinh viên và Sinh viênAddress sau đây.
Cấu hình one-to-zero-hay-một mối quan hệ sử dụng DataAnnotations:

public class Student 
{ 
    public Student() { } 

    public int StudentId { get; set; } 
    public string StudentName { get; set; } 

    public virtual StudentAddress Address { get; set; } 

} 

public class StudentAddress 
{ 
    [ForeignKey("Student")] 
    public int StudentAddressId { get; set; } 

    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public int Zipcode { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 

    public virtual Student Student { get; set; } 
} 

Khi StudentAddress thực thể không theo quy ước:

Nếu, ví dụ, StudentAddress thực thể không tuân theo quy ước cho PK tức là tên khác nhau cho thuộc tính Id thì bạn cũng cần cấu hình nó cho PK. Hãy xem xét thực thể StudentAddress sau có tên thuộc tính StudentId thay vì StudentAddressId.

public class Student 
{ 
    public Student() { } 

    public int StudentId { get; set; } 
    public string StudentName { get; set; } 

    public virtual StudentAddress Address { get; set; } 

} 

public class StudentAddress 
{ 
    [Key, ForeignKey("Student")] 
    public int StudentId { get; set; } 

    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public int Zipcode { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 

    public virtual Student Student { get; set; } 
} 

Trong ví dụ trên, chúng ta cần định cấu hình thuộc tính StudentId là Khóa cũng như khóa ngoại. Điều này sẽ làm cho tài sản StudentId trong thực thể StudentAddress là PK và FK cả hai.

Configure One-to-Zero-hoặc-One mối quan hệ sử dụng API thạo:
Khi sinh viên và StudentAddress theo các công ước: Sinh viên và StudentAddress tổ chức theo các quy ước mã đầu tiên mặc định cho PrimaryKey. Vì vậy, chúng tôi không cần phải định cấu hình chúng để xác định các khóa chính của chúng. Chúng ta chỉ cần cấu hình thực thể StudentAddress trong đó StudentAddressId phải là ForeignKey.

Ví dụ sau thiết lập mối quan hệ một hoặc không giữa Student và StudentAddress sử dụng API thông thạo.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 

    // Configure Student & StudentAddress entity 
    modelBuilder.Entity<Student>() 
       .HasOptional(s => s.Address) // Mark Address property optional in Student entity 
       .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student 

} 

Trong ví dụ trên, tổ chức Sinh viên được cấu hình sử dụng phương pháp HasOptional() mà chỉ ra rằng các StudentAddress bất động sản chuyển hướng trong tổ chức sinh viên là một tùy chọn (không cần thiết khi lưu thực thể sinh viên). Sau đó, phương thức WithRequired() cấu hình thực thể StudentAddress và làm cho thuộc tính điều hướng Student của StudentAddress theo yêu cầu (cần thiết khi lưu thực thể StudentAddress. Nó sẽ ném một ngoại lệ khi thực thể StudentAddress được lưu mà không có thuộc tính navigation của Student). Điều này sẽ làm cho StudentAddressId như ForeignKey cũng vậy. Vì vậy, bạn có thể cấu hình mối quan hệ One-to-Zero giữa hai thực thể mà thực thể Sinh viên có thể được lưu mà không cần gắn đối tượng StudentAddress vào nó nhưng thực thể StudentAddress không thể được lưu mà không cần gắn đối tượng Student entity. Điều này làm cho một đầu yêu cầu.

Khi StudentAddress thực thể không theo quy ước:
Bây giờ, chúng ta hãy xem một ví dụ về StudentAddress thực thể mà nó không tuân theo quy ước khóa chính ví dụ có tên thuộc tính Id khác với Id. Hãy xem xét các thực thể sinh viên và StudentAddress sau đây.

public class Student 
{ 
    public Student() { } 

    public int StudentId { get; set; } 
    public string StudentName { get; set; } 

    public virtual StudentAddress Address { get; set; } 

} 

public class StudentAddress 
{ 
    public int StudentId { get; set; } 

    public string Address1 { get; set; } 
    public string Address2 { get; set; } 
    public string City { get; set; } 
    public int Zipcode { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 

    public virtual Student Student { get; set; } 
} 

Bây giờ, chúng ta cần định cấu hình thuộc tính StudentId của StudentAddress cho PrimaryKey của StudentAddress cũng như ForeignKey như được hiển thị bên dưới.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    // Configure StudentId as PK for StudentAddress 
    modelBuilder.Entity<StudentAddress>() 
     .HasKey(e => e.StudentId); 

    // Configure StudentId as FK for StudentAddress 
    modelBuilder.Entity<Student>() 
       .HasOptional(s => s.Address) 
       .WithRequired(ad => ad.Student); 

} 

Configure One-to-One mối quan hệ sử dụng API thạo:
Chúng ta có thể cấu hình One-to-One mối quan hệ giữa các đơn vị sử dụng API thạo nơi cả hai đầu được yêu cầu, có nghĩa là đối tượng thực thể sinh viên phải bao gồm StudentAddress thực thể đối tượng và thực thể StudentAddress phải bao gồm đối tượng thực thể Sinh viên để lưu nó.

Lưu ý: Quan hệ một-một là về mặt kỹ thuật không thể thực hiện được trong MS SQL Server. Nó sẽ luôn luôn là một hoặc không. EF hình thành mối quan hệ One-to-One trên các thực thể không có trong DB.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    // Configure StudentId as PK for StudentAddress 
    modelBuilder.Entity<StudentAddress>() 
     .HasKey(e => e.StudentId); 

    // Configure StudentId as FK for StudentAddress 
    modelBuilder.Entity<Student>() 
       .HasRequired(s => s.Address) 
       .WithRequiredPrincipal(ad => ad.Student); 

} 

Trong ví dụ trên, modelBuilder.Entity(). HasRequired (s => s.Address) làm cho thuộc tính Địa chỉ của StudentAddress là bắt buộc. .WithRequiredPrincipal (ad => ad.Student) làm cho thuộc tính Sinh viên của thực thể StudentAddress theo yêu cầu. Vì vậy, nó cấu hình cả hai đầu cần thiết. Vì vậy, bây giờ, khi bạn cố gắng để lưu thực thể sinh viên mà không có địa chỉ hoặc thực thể StudentAddress mà không có sinh viên, nó sẽ ném một ngoại lệ.

Tham chiếu: http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx

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