2013-02-10 19 views
5

Tôi đang gặp vấn đề với việc sử dụng ValueInjecter để tạo các bản sao sâu của EntityFramework POCO vào các lớp DTO tương tự. Trong trường hợp tôi đang tiêm từ một đối tượng POCO phức tạp với nhiều thực thể liên quan/thực thể con với các thuộc tính điều hướng vào một DTO đơn giản hơn, ValueInjecter dường như vẫn đang chạm vào nhiều giá trị thuộc tính và làm chậm tải dữ liệu này từ cơ sở dữ liệu. .Sử dụng ValueInjecter để sao chép một EntityFramework POCO sang DTO mà không kích hoạt danh sách tải và thuộc tính lười biếng

Tôi tin rằng ValueInjecter nhận giá trị của mọi thuộc tính trong một đối tượng nguồn cụ thể khi nó chuẩn bị đưa các giá trị vào mục tiêu đã chỉ định.

Dự án thực tế của tôi khá phức tạp, nhưng như một ví dụ, tôi đã lấy ví dụ NerdDinner và nhân rộng vấn đề theo cách đơn giản hơn nhiều. (NerdDinner là một ví dụ về mã dev đầu tiên với EF4 (ScottGu NerdDinner Example)

Vì vậy, tôi có hai lớp mô hình

public class Dinner 
{ 
    public int DinnerId { get; set; } 
    public string Title { get; set; } 
    public DateTime EventDate { get; set; } 
    public string Address { get; set; } 
    public string HostedBy { get; set; } 
    public virtual ICollection<RSVP> Rsvps { get; set; } 
} 

public class RSVP 
{ 
    public int RsvpID { get; set; } 
    public int DinnerID { get; set; } 
    public string AttendeeEmail { get; set; } 
    public virtual Dinner Dinner { get; set; } 
} 

Tôi cũng tạo ra một lớp DTO..:

public class DinnerDTO 
{ 
    public int DinnerId { get; set; } 
    public string Title { get; set; } 
    public DateTime EventDate { get; set; } 
    public string Address { get; set; } 
    public string HostedBy { get; set; } 
} 

Lưu ý mà tôi không có bộ sưu tập Rsvps được tìm thấy trong Dinner trong số DinnerDTO của tôi.

Cũng quan trọng, tôi đang sử dụng quy ước CloneInjection để nhân bản sâu đối tượng. Mã này được đề xuất cả ở đây trên SO, cũng như nhiều trang web khác như là một cách tiếp cận để thực hiện một tiêm bản sao sâu. Mã này được tìm thấy ở đây: CloneInjection Code

Bây giờ, để nhấn mạnh occuring tải lười biếng, tôi đã đi và chèn 10.000 RSVP cho một bữa tối với Id = 1.

tôi sau đó thực hiện đoạn mã sau:

var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).FirstOrDefault(); 
DinnerDTO dinnerDTO = new DinnerDTO(); 
dinnerDTO.InjectFrom<CloneInjection>(dinner); 

Nếu tôi đặt điểm ngắt tại dòng với số InjectFrom và bước qua nó, có độ trễ đáng kể vì nó tải trọng tối đa 10.000 RSVP. Nếu tôi cũng đặt một điểm ngắt trong mã CloneInjection ở cả hai phương thức MatchSetValue, thì cả hai phương pháp này đều không được nhấn cho đến sau khi độ trễ tải đã được giải quyết. Điều này nói với tôi rằng nó phải là một cái gì đó nội bộ để ValueInjecter được phát sinh tải lười biếng của tài sản RSVPs.

Bây giờ, nếu tôi sửa đổi các mã trên như sau: (thêm một Include với truy vấn)

var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).Include("RSVPs").FirstOrDefault(); 
DinnerDTO dinnerDTO = new DinnerDTO(); 
dinnerDTO.InjectFrom<CloneInjection>(dinner); 

Sự thay đổi này buộc một "Load Háo hức" danh sách của RSVP, và như mong đợi, độ trễ là phù hợp với truy vấn và đường dây InjectFrom trước đây không bị trễ.

Tôi đã đọc qua một số bài đăng liên quan mơ hồ trên StackOverflow, một số đề xuất tắt và sau đó bật LazyLoading trên datacontext. Tôi đã thử điều đó, và trong khi nó đã làm việc, nó cảm thấy khá bẩn.

Tôi đọc qua bài này (Copying NHibernate POCO to DTO without triggering lazy load or eager load) và mã liên quan, cách tiếp cận của ông dường như đang sử dụng một số phương pháp NHibernate để xác định xem thuộc tính là proxy chưa được khởi tạo và bằng cách nào đó loại bỏ chúng ra. Tôi đã không thể tìm thấy bất cứ điều gì tương tự trong EF4.

Một phần của điều này thực sự cho tôi đi lên, đó là bộ sưu tập Rsvps không phải là ngay cả trong đối tượng DTO của tôi, tôi thậm chí không quan tâm đến giá trị của nó. Điều này dường như không đúng với tôi. Tôi không nghĩ rằng mã ValueInjecter nên thẩm vấn các giá trị của các thuộc tính mà đối tượng đích có thể thậm chí không quan tâm.

Có một số phương tiện mà tôi có thể ghi đè hành vi này trong ValueInjecter không? Bằng cách nào đó trì hoãn việc đánh giá các giá trị tài sản cho đến khi nó hoàn toàn chắc chắn tôi muốn giá trị, chẳng hạn như trong phương thức SetValue của ConventionInjection? Sau đó, ít nhất nó sẽ không được đánh giá tài sản mà DTO của tôi thậm chí không muốn. Các giải pháp tốt nhất tôi có thể nghĩ, sẽ là cho ValueInjecter, hoặc một quy ước tùy chỉnh, bằng cách nào đó có thể phát hiện một tải không tải lười biếng tài sản, và thay vì đánh giá nó, nó sẽ thay vì chỉ cần thiết lập rằng tài sản để null trên mục tiêu. Tôi không nghĩ rằng đó là có thể mặc dù.

Có cách tiếp cận nào tốt hơn thông qua EF mà tôi nên sử dụng không? Tôi không muốn tải tất cả mọi thứ trong cơ sở dữ liệu.

Tôi có tắt hoàn toàn không và vấn đề không có trong ValueInjecter?

* CHỈNH SỬA * Tôi đã tìm ra giải pháp và trả lời câu hỏi này, tôi vẫn tò mò nếu tôi chỉ làm sai hoặc nếu vẫn có cách tiếp cận tốt hơn.

Trả lời

5

Tôi cảm thấy như tôi đã tìm thấy câu trả lời thỏa đáng cho câu hỏi của riêng mình, và vì vậy tôi sẽ tự đóng cửa bản thân mình. Tôi đã làm hai việc.

Trước hết tôi đã tắt Lười tải hoàn toàn trên dbContext. Điều gì đó giống như trong hàm tạo dbContext.

this.Configuration.LazyLoadingEnabled = false;

Tôi đã không thực sự sử dụng tính năng tải lười biếng của EF, vì vậy tắt là không mất mát lớn. Điều này chỉ có nghĩa là nếu tôi muốn các thực thể liên quan được điền, tôi phải chỉ định chúng trong một số Include trên truy vấn của tôi. Không phải vấn đề lớn.

Điều khác tôi đã làm là sửa lại quy ước tiêm bản sao sâu để sử dụng mã SmartConventionInjection được tìm thấy tại đây SmartConventionInjection source. Bên cạnh việc tiêm nhanh hơn tiêm cơ sở, nó cũng không chạm vào giá trị tài sản cho đến cuộc gọi SetValue, vì vậy ngay cả khi tôi đã có một số thuộc tính tải lười, chúng sẽ không được chạm trừ khi DTO cũng có thuộc tính đó.

+3

tôi có thể hôn bạn ngay bây giờ! (theo cách thân thiện không đe dọa) –

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