Chúng tôi có một ứng dụng sử dụng SDK do nhà cung cấp của chúng tôi cung cấp để tích hợp dễ dàng với chúng. SDK này kết nối với điểm cuối AMQP và chỉ cần phân phối, lưu trữ và chuyển đổi tin nhắn cho người tiêu dùng của chúng tôi. Trước đây, sự tích hợp này vượt qua HTTP với XML dưới dạng nguồn dữ liệu và tích hợp cũ có hai cách lưu trữ DataContext - theo yêu cầu web và mỗi id luồng được quản lý. (1)
Tuy nhiên, bây giờ, chúng tôi không tích hợp qua HTTP mà là AMQP minh bạch đối với chúng tôi vì SDK đang thực hiện tất cả logic kết nối và chúng tôi chỉ còn lại việc xác định người tiêu dùng của mình nên không có tùy chọn để lưu trữ DataContext "theo yêu cầu web" chỉ mỗi id chủ đề được quản lý là còn lại. Tôi đã triển khai chuỗi mẫu trách nhiệm, vì vậy khi có bản cập nhật cho chúng tôi, nó được đặt trong một hệ thống xử lý sử dụng DataContext để cập nhật cơ sở dữ liệu theo các bản cập nhật mới. Đây là cách phương thức gọi của đường ống trông như sau:
public Task Invoke(TInput entity)
{
object currentInputArgument = entity;
for (var i = 0; i < _pipeline.Count; ++i)
{
var action = _pipeline[i];
if (action.Method.ReturnType.IsSubclassOf(typeof(Task)))
{
if (action.Method.ReturnType.IsConstructedGenericType)
{
dynamic tmp = action.DynamicInvoke(currentInputArgument);
currentInputArgument = tmp.GetAwaiter().GetResult();
}
else
{
(action.DynamicInvoke(currentInputArgument) as Task).GetAwaiter().GetResult();
}
}
else
{
currentInputArgument = action.DynamicInvoke(currentInputArgument);
}
}
return Task.CompletedTask;
}
Vấn đề là (ít nhất là những gì tôi nghĩ là) chuỗi trách nhiệm này là chuỗi các phương thức trả về / bắt đầu các tác vụ mới, vì vậy khi một bản cập nhật cho thực thể A xuất hiện, nó được xử lý bởi chủ đề được quản lý id = 1 hãy nói và sau đó chỉ sau đó một lần nữa cùng một thực thể A chỉ được xử lý bởi id được quản lý id = 2 chẳng hạn . Điều này dẫn đến:
System.InvalidOperationException: 'Một đối tượng thực thể có thể được tham chiếu bởi nhiều phiên bản của IEntityChangeTracker.'
bởi vì DataContext từ chủ đề được quản lý id = 1 đã theo dõi thực thể A. (ít nhất đó là những gì tôi nghĩ)
Câu hỏi của tôi là làm thế nào tôi có thể lưu trữ DataContext trong trường hợp của tôi? Các bạn có cùng một vấn đề? Tôi đọc này và này câu trả lời và từ những gì tôi hiểu bằng một tĩnh DataContext không phải là một lựa chọn cũng có. (2)
- Tuyên bố miễn trừ trách nhiệm: Đáng lẽ tôi phải nói rằng chúng tôi đã kế thừa ứng dụng và tôi không thể trả lời tại sao nó được triển khai như vậy.
- Tuyên bố miễn trừ trách nhiệm 2: Tôi có ít hoặc không có kinh nghiệm với EF.
Câu hỏi thường gặp:
- Phiên bản nào của EF chúng tôi đang sử dụng? 5.0
- Tại sao các thực thể sống lâu hơn bối cảnh? - Họ không nhưng có lẽ bạn đang hỏi tại sao các thực thể cần sống lâu hơn bối cảnh. Tôi sử dụng các kho lưu trữ sử dụng DataContext được lưu trong bộ nhớ cache để lấy các thực thể từ cơ sở dữ liệu để lưu trữ chúng trong bộ sưu tập trong bộ nhớ mà tôi sử dụng làm bộ đệm.
Đây là cách các thực thể được "trích xuất", trong đó DatabaseDataContext
DataContext được lưu trong bộ nhớ cache (BLOB với toàn bộ bộ cơ sở dữ liệu bên trong)
protected IQueryable<T> Get<TProperty>(params Expression<Func<T, TProperty>>[] includes)
{
var query = DatabaseDataContext.Set<T>().AsQueryable();
if (includes != null && includes.Length > 0)
{
foreach (var item in includes)
{
query = query.Include(item);
}
}
return query;
}
Sau đó, bất cứ khi nào ứng dụng khách hàng của tôi nhận được tin nhắn AMQP, chuỗi mẫu trách nhiệm của tôi bắt đầu kiểm tra xem tin nhắn này và dữ liệu của nó tôi đã xử lý chưa. Vì vậy, tôi có phương pháp trông như thế:
public async Task<TEntity> Handle<TEntity>(TEntity sportEvent)
where TEntity : ISportEvent
{
... some unimportant business logic
//save the sport
if (sport.SportID > 0) // <-- this here basically checks if so called
// sport is found in cache or not
// if its found then we update the entity in the db
// and update the cache after that
{
_sportRepository.Update(sport); /*
* because message update for the same sport can come
* and since DataContext is cached by threadId like I said
* and Update can be executed from different threads
* this is where aforementioned exception is thrown
*/
}
else // if not simply insert the entity in the db and the caches
{
_sportRepository.Insert(sport);
}
_sportRepository.SaveDbChanges();
... updating caches logic
}
Tôi nghĩ rằng việc lấy các thực thể từ cơ sở dữ liệu bằng AsNoTracking()
phương thức hoặc tách rời các thực thể mỗi khi tôi "cập nhật" hoặc "chèn" thực thể sẽ giải quyết điều này, nhưng nó đã không làm được.
SaveChanges
.