5

Trong ứng dụng kinh doanh đa cấp của chúng tôi, chúng tôi có ObservableCollections Các thực thể tự theo dõi được trả về từ các cuộc gọi dịch vụ. Ý tưởng là chúng tôi muốn có thể nhận các thực thể, thêm, cập nhật và xóa chúng từ phía máy khách thu thập, sau đó gửi các thay đổi này đến phía máy chủ, nơi chúng sẽ được lưu giữ lâu dài vào cơ sở dữ liệu.Làm thế nào để theo dõi các đối tượng bị xóa khỏi một ObservableCollection trong các kịch bản CRUD?

Thực thể tự theo dõi, như tên của chúng có thể đề xuất, tự theo dõi trạng thái của chúng. Khi một STE mới được tạo, nó có trạng thái Đã thêm, khi bạn sửa đổi thuộc tính, nó đặt trạng thái Đã sửa đổi, nó cũng có thể có Trạng thái đã xóa nhưng trạng thái này không được thiết lập khi thực thể bị xóa khỏi ObservableCollection (hiển nhiên). Nếu bạn muốn hành vi này, bạn cần tự viết mã. Trong thực hiện hiện tại của tôi, khi một thực thể bị xóa khỏi ObservableCollection, tôi giữ nó trong bộ sưu tập bóng, để khi ObservableCollection được gửi trở lại máy chủ, tôi có thể gửi các mục đã xóa cùng, do đó, Entity Framework biết để xóa chúng.

cái gì đó dọc theo dòng:

protected IDictionary<int, IList> DeletedCollections = new Dictionary<int, IList>(); 

protected void SubscribeDeletionHandler<TEntity>(ObservableCollection<TEntity> collection) 
{ 
    var deletedEntities = new List<TEntity>(); 
    DeletedCollections[collection.GetHashCode()] = deletedEntities; 

    collection.CollectionChanged += (o, a) => 
     { 
      if (a.OldItems != null) 
      { 
       deletedEntities.AddRange(a.OldItems.Cast<TEntity>()); 
      } 
     }; 
} 

Bây giờ nếu người dùng quyết định để lưu các thay đổi của mình đến máy chủ, tôi có thể nhận được danh sách các mục đã xóa, và gửi chúng cùng:

ObservableCollection<Customer> customers = MyServiceProxy.GetCustomers(); 

customers.RemoveAt(0); 

MyServiceProxy.UpdateCustomers(customers); 

Tại thời điểm này, phương thức UpdateCustomers sẽ xác minh bộ sưu tập bóng của tôi nếu có bất kỳ mục nào bị xóa và gửi chúng đến phía máy chủ.

Cách tiếp cận này hoạt động tốt, cho đến khi bạn bắt đầu nghĩ về vòng đời của các bộ sưu tập bóng tối này. Về cơ bản, khi ObservableCollection là rác được thu thập, không có cách nào để biết rằng chúng ta cần xóa bộ sưu tập bóng khỏi từ điển của mình.

Tôi đã đưa ra một số giải pháp phức tạp về cơ bản quản lý bộ nhớ thủ công trong trường hợp này. Tôi giữ một WeakReference đến ObservableCollection và cứ sau vài giây tôi kiểm tra xem tham chiếu có không hoạt động hay không, trong trường hợp này tôi xóa bộ sưu tập bóng.

Nhưng điều này có vẻ như một giải pháp khủng khiếp ... Tôi hy vọng thiên tài tập thể của StackOverflow có thể làm sáng tỏ một giải pháp tốt hơn.

EDIT:

Cuối cùng tôi quyết định đi với subclassing ObservableCollection. Mã proxy dịch vụ được tạo ra vì vậy nó là một nhiệm vụ tương đối đơn giản để thay đổi nó để trả về kiểu dẫn xuất của tôi.

Cảm ơn tất cả trợ giúp!

+0

Tại sao không giữ tham chiếu yếu cho chính các thực thể đó, chứ không phải là bộ sưu tập? Sau đó, bạn không cần phải fiddle với bộ sưu tập như là các thực thể được gỡ bỏ; chỉ cần đảm bảo các tham chiếu được hiển thị khi bạn lặp lại. –

+0

Giữ tài liệu tham khảo yếu cho các thực thể, thay vì thêm chúng vào bộ sưu tập bóng, sẽ cho phép chúng được thu gom rác và tôi muốn có thể tái sử dụng chúng tại thời điểm tôi cần cập nhật trạng thái của chúng sang cơ sở dữ liệu. Nó chỉ có ý nghĩa để cho họ được thu gom rác thải, khi các ObservableCollection whence họ đến là ra khỏi phạm vi. –

+0

Bạn có thể phân lớp ObservableCollection và thêm IDispose để thông báo mã của bạn. Nó sẽ đặt một gánh nặng trên mã khách hàng của bạn mặc dù để gọi IDispose. –

Trả lời

1

Thay vì lăn "tham chiếu yếu + phiếu thăm dò ý kiến ​​của bạn", bạn có thể sử dụng HttpRuntime.Cache (có sẵn từ tất cả các loại dự án, không chỉ các dự án web).

Thêm từng bộ sưu tập bóng vào Bộ nhớ cache, với thời gian chờ hào phóng hoặc đại biểu có thể kiểm tra xem bộ sưu tập gốc vẫn còn hoạt động (hoặc cả hai).

Nó không phải là đáng sợ khác với giải pháp của riêng bạn, nhưng nó sử dụng các thành phần cố định và đáng tin cậy .Net.

Khác hơn thế, bạn đang tìm kiếm mở rộng ObservableCollection và sử dụng rằng lớp mới thay vì (mà tôi muốn tưởng tượng là không có sự thay đổi nhỏ), hoặc thay đổi/gói UpdateCustomers phương pháp để loại bỏ các hình thức thu thập bóng DeletedCollections

Xin lỗi tôi không thể nghĩ ra bất cứ điều gì khác, nhưng hy vọng điều này sẽ giúp.
BW

+0

Cảm ơn bạn đã trả lời. Câu trả lời của bạn là làm cho tôi xem xét lại cách tiếp cận mà trước đây tôi đã từ chối như mở rộng ObservableCollection chính nó. Sẽ cần phải điều tra các tác động của việc mở rộng nó ... –

+0

Cuối cùng tôi quyết định phân lớp 'ObservableCollection'. Các lớp proxy dịch vụ được tạo ra sao cho số lượng thay đổi được giảm xuống mức tối thiểu. Cảm ơn đã giúp đỡ! –

+0

Tuyệt vời, vui mừng được giúp đỡ nhờ :) –

1

Nếu thay thế ObservableCollection là một khả năng (ví dụ: nếu bạn đang sử dụng một nhà máy chung cho tất cả các bộ sưu tập) thì bạn có thể phân lớp ObservableCollection và thêm phương thức Finalize.

Một giải pháp thay thế khác là thay đổi cách bạn tính toán mục nào sẽ bị xóa. Bạn có thể duy trì bộ sưu tập gốc và cung cấp cho khách hàng bản sao nông. Khi bộ sưu tập xuất hiện trở lại, bạn có thể so sánh cả hai để xem các mục nào không còn tồn tại nữa. Nếu các bộ sưu tập được sắp xếp, sau đó so sánh có thể được thực hiện trong thời gian tuyến tính trên kích thước của bộ sưu tập. Nếu chúng không được sắp xếp, thì các giá trị sưu tập đã sửa đổi có thể được đặt trong bảng băm và được sử dụng để tra cứu từng giá trị trong tập hợp gốc. Nếu các thực thể có một id tự nhiên, sau đó sử dụng nó như là chìa khóa là một cách an toàn để xác định các mục nào không có trong bộ sưu tập được trả về, tức là, đã bị xóa. Điều này cũng chạy trong thời gian tuyến tính.

Nếu không, giải pháp ban đầu của bạn không có vẻ xấu. Trong java, một WeakReference có thể đăng ký một cuộc gọi lại được gọi khi tham chiếu bị xóa. Không có tính năng tương tự trong .NET, nhưng việc sử dụng bỏ phiếu là một xấp xỉ gần đúng. Tôi không nghĩ cách tiếp cận này quá tệ, và nếu nó hoạt động thì tại sao lại thay đổi nó?

Ngoài ra, bạn có lo ngại về GetHashCode() trả về cùng một giá trị cho các bộ sưu tập riêng biệt không? Việc sử dụng một tham chiếu yếu tới bộ sưu tập có thể thích hợp hơn là khóa, sau đó không có khả năng xảy ra xung đột.

+0

Khi phân lớp, tôi sẽ không cần phải bận tâm với Finalizing. Các bộ sưu tập bóng không bao giờ được tham chiếu từ nơi khác, và phạm vi của nó được gắn với nguồn gốc 'Observablecollection'. Giữ trạng thái trên máy chủ không phải là một khả năng và cách tiếp cận này sẽ không cho phép tôi chỉ gửi lại các thực thể đã xóa để giảm tải trọng chuyển giao chẳng hạn. Tuy nhiên, phần về 'GetHashCode()' va chạm là thứ tôi sẽ cần giải quyết nếu tôi quyết định không phân lớp 'ObservableCollection'. Tuy nhiên, một lý do khác để xem xét sau này :) Cảm ơn bạn đã trả lời! –

+0

Bạn đúng về việc không cần hoàn thành nếu phân lớp - bạn có thể làm cho các thành viên đã xóa liệt kê thành viên của bộ sưu tập. Một khi bạn nhận thấy, điều này được xung quanh vấn đề hashCode, vì đó không còn cần thiết nữa. Tuy nhiên, giải pháp hiện tại của bạn, bỏ phiếu yếu kém trên một chủ đề nền - có phải là xấu như vậy? – mdma

1

Tôi nghĩ rằng bạn đang trên một con đường tốt, tôi sẽ xem xét tái cấu trúc trong tình huống này. Kinh nghiệm của tôi là trong 99% các trường hợp, bộ thu gom rác giúp việc quản lý bộ nhớ trở nên tuyệt vời - hầu như không có công việc thực sự cần thiết.

nhưng trong 1% các trường hợp, người dùng phải nhận ra rằng họ đã phải nâng cấp và đi "trường học cũ" bằng cách tăng cường bộ nhớ đệm/bộ nhớ trong các khu vực đó. mũ cho bạn để nhận ra bạn đang ở trong tình huống đó và cố gắng tránh các thủ thuật IDispose/WeakReference. Tôi nghĩ bạn sẽ thực sự giúp anh chàng tiếp theo làm việc trong mã của bạn.

Như để có được một giải pháp, tôi nghĩ rằng bạn đã có một va li tốt về tình hình

-be rõ ràng khi đối tượng của bạn cần phải được tạo ra -be rõ ràng khi đối tượng của bạn cần phải bị tiêu diệt -be rõ ràng khi đối tượng của bạn cần được đẩy tới máy chủ

chúc may mắn! hãy cho chúng tôi biết cách hoạt động của nó :)

+0

Cảm ơn, cuối cùng tôi đã kết thúc chucking mã mặc dù. Phân lớp có ý nghĩa hơn vì nó gắn phạm vi của bộ sưu tập bóng vào 'ObservableCollection'. –