2011-01-11 32 views
13

Tôi có mối quan hệ 1 .. * giữa Đánh giáĐề xuất.ASP.NET MVC/EF4/POCO/Repository - Cách cập nhật mối quan hệ?

Phần liên quan của mô hình của tôi (mà cũng là POCO ánh xạ bởi EF4):

public class Review 
{ 
    public ICollection<Recommendations> Recommendations { get; set; } 
} 

Trên một Chỉnh sửa Xem, tôi đại diện cho Khuyến nghị như một tập hợp các hộp kiểm.

Khi tôi cố gắng và thêm một Khuyến nghị mới như một phần của biên tập Tạp chí (ví dụ như kiểm tra hộp khác), không có gì đang xảy ra - và tôi biết tại sao ...

tôi sử dụng "kỹ thuật sơ khai" để cập nhật các thực thể của tôi - ví dụ: tôi tạo một thực thể có cùng khóa, đính kèm nó vào biểu đồ, sau đó thực hiện ApplyCurrentValues. Nhưng điều này chỉ hoạt động cho các thuộc tính vô hướng, không phải cho các thuộc tính điều hướng.

Tôi tìm thấy this StackOverflow question có vẻ tốt, nhưng tôi đang cố gắng tìm hiểu cách làm việc này với POCO's/Repository (và ngữ cảnh tách rời ASP.NET MVC).

Vì tôi đang sử dụng POCO, review.RecommendationsICollection<Recommendation>, vì vậy tôi không thể làm review.Recommendations.Attach. Tôi cũng không sử dụng các thực thể tự theo dõi, vì vậy tôi cần phải làm việc theo cách thủ công với theo dõi đồ thị/thay đổi - điều này đã không còn là vấn đề cho đến bây giờ.

Vì vậy, bạn có thể hình dung ra kịch bản:

Đánh giá:

  • khuyến nghị (ICollection<Recommendation>):
    • RecommendationOne (Recommendation)
    • RecommendationTwo (Recommendation)

Nếu im trên chế độ xem chỉnh sửa, hai trong số các hộp kiểm đã được chọn. Phần thứ ba (đại diện cho RecommendationThree) là không được chọn.

Nhưng nếu tôi kiểm tra hộp đó, mô hình trên trở thành:

Đánh giá:

  • khuyến nghị (ICollection<Recommendation>):
    • RecommendationOne (Recommendation)
    • RecommendationTwo (Recommendation)
    • Đề xuấtThree (Recommendation)

Và vì vậy tôi cần phải đính kèm RecommendationThree để đồ thị như một thực thể mới .

Tôi có cần các trường ẩn để so sánh dữ liệu đã đăng đối với thực thể hiện tại không? Hoặc tôi nên lưu trữ các thực thể trong TempData và so sánh với thực thể được đăng?

EDIT

Để tránh nhầm lẫn, đây là đầy đủ ứng dụng ngăn xếp cuộc gọi:

ReviewController

[HttpPost] 
public ActionResult Edit(Review review) 
{ 
    _service.Update(review); // UserContentService 
    _unitOfWork.Commit(); 
} 

UserContentService

public void Update<TPost>(TPost post) where TPost : Post, new() 
{ 
    _repository.Update(post); // GenericRepository<Post> 
} 

GenericRepository - sử dụng như GenericRepository<Post>

public void Update<T2>(T2 entity) where T2 : class, new() 
{ 
    // create stub entity based on entity key, attach to graph. 

    // override scalar values 
    CurrentContext.ApplyCurrentValues(CurrentEntitySet, entity); 
} 

Vì vậy, Update (hoặc Add hoặc Delete) phương pháp Repository cần phải được gọi cho mỗi giới thiệu, tùy thuộc nó mới/sửa đổi/xóa.

Trả lời

4

Có lẽ tôi cần bối cảnh nhiều hơn nhưng whats sai với:

recommendations.Add(newRecomendation) 

?

Trong bài trả lời bình luận:

Ok vậy whats sai với

SomeServiceOrRepository.AddNewRecommendation(newRecommendation) 

hoặc

SomeServiceOrRepository.AddNewRecommendation(int parentId, newRecommendation) 

câu cuối? Bạn có nghĩa là hai câu hỏi?

Điều này không khó chút nào.

Để tóm tắt câu trả lời của tôi, tôi nghĩ bạn đang làm những điều "khó" và thực sự nên tập trung vào việc đăng các giá trị biểu mẫu tương ứng với hành động CRUD mà bạn đang cố gắng hoàn thành.

Nếu một thực thể mới có thể đến cùng một lúc với các thực thể đã chỉnh sửa của bạn, bạn nên thực sự thêm tiền tố cho chúng khác nhau để trình kết nối mô hình có thể nhận được. Ngay cả khi bạn có nhiều mục mới, bạn có thể sử dụng cùng cú pháp [0] chỉ cần thêm tiền tố vào trường "tên" bằng Mới hoặc một cái gì đó.

Rất nhiều lần trong trường hợp này, bạn không thể dựa vào các tính năng đồ thị của khung thực thể vì việc xóa một thực thể khỏi bộ sưu tập không bao giờ có nghĩa là nó sẽ được đặt để xóa.

Nếu hình thức là không thay đổi, bạn cũng có thể thử bằng cách sử dụng generized đính kèm chức năng tắt của ObjectSet:

theContect.ObjectSet<Review>().Attach(review) 

Tấn cách thoát ra khỏi đây. Có lẽ bạn có thể đăng bộ điều khiển và xem mã?

+0

chỉ thêm mục vào bộ sưu tập, tôi cũng cần thêm đối tượng đó vào biểu đồ. nhớ - bối cảnh tách rời, POCO, không có STE. trong những tình huống này, EF không biết rằng đề xuất này cần phải được thêm vào DB-i cần phải nói như vậy. – RPM1984

+0

trả lời - chỉnh sửa. và làm cách nào để tôi biết * rằng đề xuất đó nên được thêm/sửa đổi/xóa? sao tôi cần phải so sánh tất cả các khuyến nghị "cũ" với những khuyến nghị mới? nhìn vào câu cuối cùng trong câu hỏi. – RPM1984

+0

@jfar - câu hỏi đã chỉnh sửa. đọc chỉnh sửa của bạn - hãy nhớ sử dụng 'ApplyCurrentValues'. 'Đính kèm (đánh giá)' sẽ chỉ sửa đổi các giá trị vô hướng - không phải đề xuất. – RPM1984

6

Làm việc với biểu đồ đối tượng tách rời là nhược điểm yêu thích của tôi về EF. Đơn giản chỉ cần đau trong ass. Trước tiên, bạn phải tự mình xử lý nó. EF sẽ không giúp bạn với nó. Điều đó có nghĩa là ngoài Review bạn cũng phải gửi một số thông tin về các thay đổi đã thực hiện. Khi bạn đính kèm Review vào ngữ cảnh, nó đặt Review tất cả Recommendationtất cả các mối quan hệ đến Unchanged trạng thái. ApplyCurrentValues chỉ hoạt động đối với các giá trị vô hướng như bạn đã tìm thấy. Vì vậy, bạn phải sử dụng thông tin bổ sung của mình về các thay đổi đã thực hiện và đặt trạng thái quan hệ thành Added bằng cách sử dụng ObjectContext.ObjectStateManager.ChangeRelationshipState.

Tôi personaly đã từ bỏ phương pháp này và tôi đang tải đồ thị đối tượng từ DB đầu tiên hợp nhất các thay đổi của tôi vào biểu đồ đính kèm và lưu nó.

Tôi đã trả lời câu hỏi tương tự more deeply here.

+1

"Tôi personaly đã từ bỏ cách tiếp cận này và tôi đang tải đồ thị đối tượng từ DB đầu tiên sáp nhập các thay đổi của tôi vào biểu đồ đính kèm và lưu nó." - đó là * chính xác * những gì tôi đã làm, lol. – RPM1984

+0

Sau khi chi tiêu một vài ngày về điều này và cuối cùng bị mắc kẹt trên 'ChangeRelationshipState' từ chối làm việc với' EntityState.Modified', tôi cũng đã từ bỏ và kích hoạt tính năng Foreign Key. [Bài đăng trên blog] của bạn (http://www.ladislavmrnka.com/2011/05/foreign-key-vs-independent-associations-in-ef-4/) là một bài đọc thú vị. – Stijn

+0

@Stijn: Quan hệ không thể sửa đổi trạng thái. Thay đổi quan hệ có nghĩa là xóa mối quan hệ cũ và tạo ra một mối quan hệ mới. –

8

Tôi đã chấp nhận câu trả lời của @ jfar bởi vì anh ấy đã cho tôi đi đúng hướng, nhưng tôi nghĩ tôi sẽ thêm câu trả lời ở đây vì lợi ích của người khác.

Lý do các mối quan hệ không được cập nhật là vì các lý do sau:

1) Kịch bản hoàn toàn bị ngắt kết nối. ASP.NET = không trạng thái, bối cảnh mới đã tạo mới mỗi yêu cầu HTTP.

2) Thực thể được chỉnh sửa được tạo bởi MVC (ràng buộc mô hình), nhưng không tồn tại trong biểu đồ.

3) Khi sử dụng POCO không theo dõi thay đổi, thực hiện .Attach trên thực thể sẽ thêm nó vào biểu đồ, nhưng thực thể và mọi mối quan hệ con sẽ là Không thay đổi.

4) Tôi sử dụng mẹo thực thể sơ khai và ApplyCurrentValues để cập nhật thực thể, nhưng điều này chỉ hoạt động đối với các thuộc tính vô hướng, chứ không chỉ cho các thuộc tính điều hướng.

Vì vậy - để có được ở trên để làm việc, tôi sẽ phải thiết lập các explicity EntityState cho đối tượng (mà xảy ra tự động vì ApplyCurrentValues), và cũng các thuộc tính định hướng.

Và có vấn đề - làm cách nào để tôi biết nếu thuộc tính điều hướng đã được thêm/sửa/xóa? Tôi không có đối tượng nào để so sánh - chỉ một thực thể mà tôi biết là "đã chỉnh sửa", nhưng tôi không biết nội dung nào đã được chỉnh sửa.

Vì vậy, giải pháp cuối cùng là thế này:

[HttpPost] 
public ActionResult Edit(Review review) 
{ 
    var existingReview = _service.FindById(review.Id); // review is now in graph. 
    TryUpdateModel(existingReview); // MVC equivalent of "ApplyCurrentValues" - but works for ALL properties - including navigationals 
    _unitOfWork.Commit(); // save changed 
} 

Vậy là xong. Tôi thậm chí không cần phương pháp _service.Update của mình - vì tôi không cần thủ thuật còn sơ khai nữa - bởi vì bài đánh giá có trong biểu đồ với truy xuất và ApplyCurrentValues được thay thế bằng TryUpdateModel.

Bây giờ tất nhiên - đây không phải là giải pháp concurrency-proof.

Nếu tôi tải Chế độ xem chỉnh sửa đánh giá và trước khi tôi nhấp vào "Gửi" người khác thay đổi Đánh giá, thay đổi của tôi có thể bị mất.

May mắn thay tôi có chế độ đồng thời "cuối cùng trong chiến thắng", vì vậy nó không phải là vấn đề đối với tôi.

Tôi thích POCO, nhưng người đàn ông là họ đau khi bạn có sự kết hợp của một môi trường không quốc tịch (MVC) và không có theo dõi thay đổi.

+0

Đây có thể là lỗ hổng bảo mật khá lớn khi làm việc với mô hình tự động ràng buộc vì yêu cầu độc hại cũng có thể gửi các trường đã sửa đổi thường không thể chỉnh sửa trên biểu mẫu. –

+1

@Ladislav Mrnka - Đó là lý do bạn chuyển danh sách loại trừ cho quá tải 'TryUpdateModel'. Ở trên chỉ là một ví dụ đơn giản. – RPM1984

+0

@ RPM1984, có cách nào toàn diện để phản ánh mô hình nhận được từ khách hàng, cùng với tất cả các thuộc tính điều hướng của nó, cả đơn lẻ và bộ sưu tập đến cửa hàng - bao gồm xóa các thực thể được khách hàng xóa? – Shimmy

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