2013-02-21 37 views
13

Có bao giờ là một ý tưởng hay để làm việc trực tiếp với ngữ cảnh không? Ví dụ: giả sử tôi có cơ sở dữ liệu về khách hàng và người dùng có thể tìm kiếm theo tên, hiển thị danh sách, chọn danh sách, sau đó chỉnh sửa thuộc tính của khách hàng đó.Thực thể tốt nhất và thực hành tốt nhất của WPF

Có vẻ như tôi nên sử dụng ngữ cảnh để nhận danh sách khách hàng (ánh xạ tới POCO hoặc CustomerViewModels) và sau đó đóng ngay lập tức ngữ cảnh. Sau đó, khi người dùng chọn một trong số CustomerViewModels trong danh sách, phần thuộc tính khách hàng của giao diện người dùng sẽ điền.

Tiếp theo, họ có thể thay đổi tên, loại, địa chỉ trang web, kích thước công ty, v.v. Sau khi nhấn nút lưu, tôi mở ngữ cảnh mới, sử dụng ID từ CustomerViewModel để truy xuất hồ sơ khách hàng đó và cập nhật từng tính chất của nó. Cuối cùng, tôi gọi SaveChanges() và đóng ngữ cảnh. Đây là rất nhiều công việc.

Câu hỏi của tôi là tại sao không chỉ làm việc trực tiếp với bối cảnh để nó mở trong suốt? Tôi đã đọc bằng cách sử dụng bối cảnh tương tự với một phạm vi lâu dài là rất xấu và chắc chắn sẽ gây ra vấn đề. Giả định của tôi là nếu ứng dụng sẽ chỉ được sử dụng bởi MỘT người tôi có thể rời khỏi bối cảnh mở và làm mọi thứ. Tuy nhiên, nếu có nhiều người dùng, tôi muốn duy trì một đơn vị công việc ngắn gọn và do đó mở và đóng ngữ cảnh theo yêu cầu.

Mọi đề xuất? Cảm ơn.


@PGallagher - Cảm ơn bạn đã trả lời kỹ lưỡng.
@Brice - đầu vào của bạn cũng hữu ích là

Tuy nhiên, @Manos D. nhận xét 'thu nhỏ của mã dự phòng' liên quan đến tôi một chút. Hãy để tôi đi qua một ví dụ. Cho phép nói rằng tôi đang lưu trữ khách hàng trong cơ sở dữ liệu và một trong những thuộc tính khách hàng của tôi là CommunicationMethod.

[Flags] 
public enum CommunicationMethod 
{ 
    None = 0, 
    Print = 1, 
    Email = 2, 
    Fax = 4 
} 

Giao diện người dùng cho trang quản lý khách hàng trong WPF sẽ chứa ba hộp kiểm theo phương thức liên lạc của khách hàng (In, Email, Fax). Tôi không thể ràng buộc mỗi hộp kiểm với enum đó, nó không có ý nghĩa. Ngoài ra, điều gì sẽ xảy ra nếu người dùng nhấp vào khách hàng đó, hãy thức dậy và đi ăn trưa ... ngữ cảnh ngồi đó hàng giờ đồng hồ. Thay vào đó, đây là quá trình suy nghĩ của tôi.

Người dùng cuối chọn khách hàng từ danh sách. Tôi mới lên một bối cảnh, thấy rằng khách hàng và trả về một CustomerViewModel, sau đó bối cảnh được đóng lại (tôi đã để lại kho lưu trữ ra cho đơn giản ở đây).

using(MyContext ctx = new MyContext()) 
{ 
    CurrentCustomerVM = new CustomerViewModel(ctx.Customers.Find(customerId)); 
} 

Bây giờ người dùng có thể kiểm tra/bỏ chọn các nút In, Email, Fax khi chúng được ràng buộc với ba thuộc tính bool trong CustomerViewModel, cũng có phương thức Save(). Đây rồi.

public class CustomerViewModel : ViewModelBase 
{ 
    Customer _customer; 

    public CustomerViewModel(Customer customer) 
    { 
     _customer = customer; 
    } 


    public bool CommunicateViaEmail 
    { 
     get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email); } 
     set 
     { 
      if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email)) return; 

      if (value) 
       _customer.CommunicationMethod |= CommunicationMethod.Email; 
      else 
       _customer.CommunicationMethod &= ~CommunicationMethod.Email; 
     } 
    } 
    public bool CommunicateViaFax 
    { 
     get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax); } 
     set 
     { 
      if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax)) return; 

      if (value) 
       _customer.CommunicationMethod |= CommunicationMethod.Fax; 
      else 
       _customer.CommunicationMethod &= ~CommunicationMethod.Fax; 
     } 
    } 
    public bool CommunicateViaPrint 
    { 
     get { return _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print); } 
     set 
     { 
      if (value == _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print)) return; 

      if (value) 
       _customer.CommunicateViaPrint |= CommunicationMethod.Print; 
      else 
       _customer.CommunicateViaPrint &= ~CommunicationMethod.Print; 
     } 
    } 

    public void Save() 
    { 
     using (MyContext ctx = new MyContext()) 
     { 
      var toUpdate = ctx.Customers.Find(_customer.Id); 
      toUpdate.CommunicateViaEmail = _customer.CommunicateViaEmail; 
      toUpdate.CommunicateViaFax = _customer.CommunicateViaFax; 
      toUpdate.CommunicateViaPrint = _customer.CommunicateViaPrint; 

      ctx.SaveChanges(); 
     } 
    } 
} 

Bạn có thấy điều gì sai về điều này không?

Trả lời

17

Bạn có thể sử dụng ngữ cảnh chạy dài; bạn chỉ cần nhận thức được những tác động.

Ngữ cảnh đại diện cho một đơn vị công việc. Bất cứ khi nào bạn gọi SaveChanges, tất cả các thay đổi đang chờ xử lý đối với các thực thể đang được theo dõi sẽ được lưu vào cơ sở dữ liệu. Bởi vì điều này, bạn sẽ cần phải phạm vi mỗi bối cảnh cho những gì có ý nghĩa. Ví dụ: nếu bạn có tab để quản lý khách hàng và một tab khác để quản lý sản phẩm, bạn có thể sử dụng một ngữ cảnh cho mỗi sản phẩm để khi người dùng nhấp vào lưu trên tab khách hàng, tất cả thay đổi họ thực hiện cho sản phẩm cũng không được lưu.

Có rất nhiều thực thể được theo dõi bởi một ngữ cảnh cũng có thể làm chậm DetectChanges. Một cách để giảm thiểu điều này là sử dụng proxy theo dõi thay đổi.

Vì thời gian giữa việc tải một thực thể và lưu thực thể đó có thể khá dài, cơ hội đánh một ngoại lệ đồng thời lạc quan lớn hơn so với các ngữ cảnh ngắn ngủi. Những ngoại lệ này xảy ra khi một thực thể được thay đổi bên ngoài giữa tải và lưu nó. Handling these exceptions là khá đơn giản, nhưng nó vẫn còn một cái gì đó để được nhận thức.

Một điều thú vị bạn có thể thực hiện với ngữ cảnh lâu dài trong WPF là liên kết với thuộc tính DbSet.Local (ví dụ: context.Customers.Local). đây là ObservableCollection chứa tất cả các thực thể được theo dõi không được đánh dấu để xóa.

Hy vọng điều này sẽ cung cấp cho bạn thêm một chút thông tin để giúp bạn quyết định phương pháp trợ giúp nào.

+0

Câu trả lời hay. Cảm ơn bạn đã trả lời: câu trả lời của một thành viên nhóm EF luôn có giá trị ở đây. – JYL

0

Ngữ cảnh không được kết nối vĩnh viễn với cơ sở dữ liệu. Nó chủ yếu là một bộ nhớ đệm trong bộ nhớ mà bạn đã tải từ đĩa. Nó sẽ chỉ yêu cầu các bản ghi từ cơ sở dữ liệu khi bạn yêu cầu một bản ghi mà nó chưa được tải trước đó, nếu bạn buộc nó phải làm mới hoặc khi bạn đang lưu lại các thay đổi của mình vào đĩa.

Mở một ngữ cảnh, lấy một bản ghi, đóng ngữ cảnh và sau đó sao chép các thuộc tính đã sửa đổi vào một đối tượng từ ngữ cảnh hoàn toàn mới là hình mẫu của mã dự phòng. Bạn có nghĩa vụ phải rời khỏi bối cảnh ban đầu một mình và sử dụng nó để làm SaveChanges().

Nếu bạn đang tìm cách giải quyết các vấn đề về tương tranh, bạn nên thực hiện tìm kiếm trên google về "xử lý đồng thời" cho phiên bản khung thực thể của bạn.

Ví dụ: tôi đã tìm thấy this.

Chỉnh sửa để đáp ứng với bình luận:

Vì vậy, từ những gì tôi hiểu bạn cần một tập hợp con của các cột của một kỷ lục được ghi đè với các giá trị mới trong khi phần còn lại không bị ảnh hưởng? Nếu vậy, có, bạn sẽ cần phải cập nhật thủ công vài cột này trên đối tượng "mới".

Tôi đã có ấn tượng rằng bạn đang nói về một biểu mẫu phản ánh tất cả các trường của đối tượng khách hàng và có nghĩa là cung cấp quyền truy cập chỉnh sửa vào toàn bộ hồ sơ khách hàng. Trong trường hợp này, không có vấn đề gì khi sử dụng ngữ cảnh mới và sao chép cẩn thận tất cả các thuộc tính từng cái một, bởi vì kết quả cuối cùng (tất cả dữ liệu được ghi đè với các giá trị biểu mẫu bất kể tuổi tác) sẽ giống nhau.

+0

xem cập nhật bài đăng của tôi giải thích lý do tôi sử dụng CustomerViewModel chứ không phải ngữ cảnh – BBauer42

3

Microsoft tham khảo:

http://msdn.microsoft.com/en-gb/library/cc853327.aspx

Họ nói;

Giới hạn phạm vi của ObjectContext

Trong hầu hết các trường hợp, bạn nên tạo một thể hiện ObjectContext trong một tuyên bố sử dụng (Sử dụng ... End Using trong Visual Basic).

Điều này có thể tăng hiệu suất bằng cách đảm bảo rằng các tài nguyên được liên kết với ngữ cảnh đối tượng được tự động xử lý khi mã thoát khỏi khối câu lệnh.

Tuy nhiên, khi điều khiển được liên kết với đối tượng bởi bối cảnh đối tượng quản lý, dụ ObjectContext nên được duy trì miễn là ràng buộc là cần thiết và xử lý bằng tay.

Để biết thêm thông tin, hãy xem Quản lý tài nguyên trong Dịch vụ đối tượng (Khuôn khổ thực thể). http://msdn.microsoft.com/en-gb/library/bb896325.aspx

Điều nào nói;

Trong ngữ cảnh đối tượng dài hạn, bạn phải đảm bảo rằng ngữ cảnh là được xử lý khi không còn yêu cầu.


StackOverflow tham khảo:

câu hỏi StackOverflow này cũng có một số câu trả lời hữu ích ...

Entity Framework Best Practices In Business Logic?

đâu một vài gợi ý mà bạn quảng bá nội dung của bạn đến một cấp cao hơn và tham khảo nó từ đây, do đó chỉ giữ một ngữ cảnh duy nhất.


mười xu của tôi có giá trị:

Bao bì các bối cảnh trong một Bản Tuyên Bố Sử dụng, cho phép người thu gom rác để làm sạch các nguồn lực, và ngăn chặn rò rỉ bộ nhớ. Rõ ràng là trong các ứng dụng đơn giản, đây không phải là vấn đề, tuy nhiên, nếu bạn có nhiều màn hình, tất cả đều sử dụng rất nhiều dữ liệu, bạn có thể gặp rắc rối, trừ khi bạn chắc chắn Vứt bỏ bối cảnh của bạn một cách chính xác.

Do đó tôi đã sử dụng phương pháp tương tự như phương pháp bạn đã đề cập, nơi tôi đã thêm phương thức AddOrUpdate vào mỗi Vùng lưu trữ của tôi. nó có tồn tại.


Đang cập nhật Thuộc tính Entity:

Về việc cập nhật tính tuy nhiên, tôi đã sử dụng một chức năng đơn giản trong đó sử dụng phản ánh để sao chép tất cả các thuộc tính từ một Entity để khác;

Public Shared Function CopyProperties(Of sourceType As {Class, New}, targetType As {Class, New})(ByVal source As sourceType, ByVal target As targetType) As targetType 
    Dim sourceProperties() As PropertyInfo = source.GetType().GetProperties() 
    Dim targetProperties() As PropertyInfo = GetType(targetType).GetProperties() 

    For Each sourceProp As PropertyInfo In sourceProperties 
     For Each targetProp As PropertyInfo In targetProperties 
      If sourceProp.Name <> targetProp.Name Then Continue For 

      ' Only try to set property when able to read the source and write the target 
      ' 
      ' *** Note: We are checking for Entity Types by Checking for the PropertyType to Start with either a Collection or a Member of the Context Namespace! 
      ' 
      If sourceProp.CanRead And _ 
        targetProp.CanWrite Then 
       ' We want to leave System types alone 
       If sourceProp.PropertyType.FullName.StartsWith("System.Collections") Or (sourceProp.PropertyType.IsClass And _ 
         sourceProp.PropertyType.FullName.StartsWith("System.Collections")) Or sourceProp.PropertyType.FullName.StartsWith("MyContextNameSpace.") Then 
        ' 
        ' Do Not Store 
        ' 
       Else 

        Try 

         targetProp.SetValue(target, sourceProp.GetValue(source, Nothing), Nothing) 

        Catch ex As Exception 

        End Try 

       End If 
      End If 

      Exit For 
     Next 
    Next 

    Return target 
End Function 

Tôi làm điều gì đó tương tự;

dbColour = Classes.clsHelpers.CopyProperties(Of Colour, Colour)(RecordToSave, dbColour) 

Điều này làm giảm số lượng mã tôi cần viết cho mỗi Kho lưu trữ tất nhiên!

+0

Cảm ơn bạn đã nhận xét kỹ lưỡng. Bạn có thấy điều gì sai khi cập nhật OP mà tôi đã thực hiện theo quy tắc ngang không? Cảm ơn một lần nữa. – BBauer42

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