2011-12-20 24 views
7

Nhiều lỗi mà tôi đã sửa gần đây là kết quả của tham chiếu null khi truy cập các thuộc tính điều hướng của các đối tượng được nạp bằng khung thực thể. Tôi tin rằng phải có một lỗ hổng trong cách tôi đang thiết kế các phương pháp của tôi. Dưới đây là ví dụ ...Tránh NullReferenceException khi truy cập EF Navigation Properties

Nhiệm vụ chứa nhiều vai trò, mỗi vai trò tham chiếu đến người dùng.

public class Role 
{ 
    public int Id; 
    public int User_Id; 
    public string Type; 
} 

public class User 
{ 
    public int Id 
    public string Name; 
}  

public class Task 
{ 
    public int Id; 
    public string Name; 
    public string Status; 
    public List<Role> Roles; 
} 

Xét rằng tôi sẽ truy vấn bối cảnh của tôi như này do nhầm lẫn và không được nạp tài ...

var task = context.Tasks.Include(x=>x.Roles).FirstOrDefault; 

Và sau đó tôi gọi phương thức này ...

public void PrintTask(Task task) 
{ 
    Console.WriteLine(task.Name); 
    Console.WriteLine(task.Status); 

    foreach(var r in task.Roles) 
    { 
     Console.WriteLine(r.User.Name); //This will throw NRE because User wasn't loaded 
    } 
} 

Tôi có thể đã xây dựng phương pháp này với mọi ý định để tải Vai trò và Người dùng nhưng lần sau tôi sử dụng nó tôi có thể quên rằng tôi cần cả hai. Lý tưởng nhất là định nghĩa phương thức nên cho tôi biết dữ liệu nào là cần thiết, nhưng ngay cả khi tôi chuyển vào cả Task và Role, tôi vẫn còn thiếu Roles-> User.

Cách thích hợp để tham chiếu các mối quan hệ này và đảm bảo rằng chúng được tải bằng thứ gì đó như phương pháp in này? Tôi quan tâm đến một thiết kế tốt hơn, do đó, "Sử dụng tải Lazy" không phải là câu trả lời tôi đang tìm kiếm.

Cảm ơn!

EDIT:

Tôi biết tôi có thể tải các nhiệm vụ như thế này ...

var task = context.Tasks.Include(x=>x.Roles.Select(z=>z.User)).FirstOrDefault(); 

Những gì tôi muốn biết là làm thế nào để thiết kế phương pháp của tôi để khi tôi quay trở lại và sử dụng nó 6 tháng kể từ bây giờ tôi biết dữ liệu nào cần được tải trong các thực thể của tôi? Định nghĩa phương thức không chỉ ra những gì cần thiết để sử dụng nó. Hoặc làm thế nào để tôi chống lại những NullReferences. Phải có một thiết kế tốt hơn.

+0

thể trùng lặp của [ Một NullReferenceException trong .NET là gì?] (Http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net) –

+0

Điều này không khác với bất kỳ vấn đề 'NullReferenceException' nào khác. –

Trả lời

1

Câu hỏi rất hay. Dưới đây là một số giải pháp có thể có, trong khi chúng không thực thi việc tránh NRE, chúng sẽ cung cấp manh mối cho người gọi rằng họ cần phải Include điều:

Tùy chọn đầu tiên là không có phương pháp truy cập của bạn tài sản đảm bảo của một thực thể; đúng hơn, buộc người gọi để vượt qua tất cả các đối tượng:

public void PrintTask(Task task, User taskUser) 
{ 
    // ... 
} 

Một lựa chọn khác là đặt tên các tham số của phương pháp của bạn như vậy mà nó sẽ đầu mối người gọi như những gì được yêu cầu:

public void PrintTask(Task taskWithUser) 
{ 
    // ... 
} 
+0

Cảm ơn. Tôi nghĩ rằng bạn đã xác nhận những suy nghĩ của tôi rằng không có giải pháp thuần túy nào cho điều này. Tôi cố gắng giữ quyền truy cập tài sản càng đơn giản càng tốt và chuyển chúng riêng lẻ khi có thể. – BZink

2

Bạn có thể sử dụng phương pháp mở rộng Select để tải mong muốn Users.

var task = context.Tasks.Include(x => x.Roles) 
      .Include(x => x.Roles.Select(r => r.User)) 
      .FirstOrDefault(); 

Edit:

Có vài cách mà tôi có thể nghĩ ra để tránh những TNMT

  • thử nghiệm tích hợp sử dụng một cơ sở dữ liệu SQL Server CE/Express. Kiểm tra đơn vị với ngữ cảnh giả sẽ không hoạt động chính xác.
  • Đang tải các đối tượng gần nơi chúng được tiêu thụ. Vì vậy, Include s ở gần nơi các thực thể được sử dụng.
  • Chuyển DTO/Chế độ xem sang các lớp phía trên mà không vượt qua các đối tượng .
+0

Xin lỗi, tôi không nói rõ rằng tôi biết cách tải người dùng. Và trên thực tế, bạn có thể làm điều đó trong một tuyên bố Bao gồm, không phải hai. Những gì tôi đang đối phó với là sử dụng các phương pháp mà nó không rõ ràng những gì tài liệu tham khảo là cần thiết. Vì vậy, nếu tôi tải thực thể sai, và sử dụng phương pháp, tôi nhận được tham chiếu null. – BZink

+0

@BZink câu trả lời cập nhật – Eranga

1

User nên lười biếng nạp trong báo cáo loop-chỉ của bạn mặc dù rằng đây là một vấn đề select N + 1 cổ điển mà bạn nên sửa chữa với Include khác.

Tôi nghĩ vấn đề gốc rễ là một trong hai mà đặc biệt Role này không một User, hoặc Role này đặc biệt 's User có rỗng bộ cho Name của nó. Bạn cần phải kiểm tra cả hai giá trị rỗng trong vòng lặp của mình

foreach(var r in task.Roles) 
{ 
    if (r.User != null) 
     Console.WriteLine(r.User.Name ?? "Name is null"); 
} 
Các vấn đề liên quan