Lõi khung thực thể: Hoạt động thứ hai bắt đầu trên ngữ cảnh này trước khi hoạt động trước đó hoàn thành


89

Tôi đang làm việc trên một dự án ASP.Net Core 2.0 sử dụng Entity Framework Core

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0"/>

Và trong một trong các phương pháp danh sách của tôi, tôi gặp lỗi này:

InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

Đây là phương pháp của tôi:

    [HttpGet("{currentPage}/{pageSize}/")]
    [HttpGet("{currentPage}/{pageSize}/{search}")]
    public ListResponseVM<ClientVM> GetClients([FromRoute] int currentPage, int pageSize, string search)
    {
        var resp = new ListResponseVM<ClientVM>();
        var items = _context.Clients
            .Include(i => i.Contacts)
            .Include(i => i.Addresses)
            .Include("ClientObjectives.Objective")
            .Include(i => i.Urls)
            .Include(i => i.Users)
            .Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search))
            .OrderBy(p => p.CompanyName)
            .ToPagedList(pageSize, currentPage);

        resp.NumberOfPages = items.TotalPage;

        foreach (var item in items)
        {
            var client = _mapper.Map<ClientVM>(item);

            client.Addresses = new List<AddressVM>();
            foreach (var addr in item.Addresses)
            {
                var address = _mapper.Map<AddressVM>(addr);
                address.CountryCode = addr.CountryId;
                client.Addresses.Add(address);
            }

            client.Contacts = item.Contacts.Select(p => _mapper.Map<ContactVM>(p)).ToList();
            client.Urls = item.Urls.Select(p => _mapper.Map<ClientUrlVM>(p)).ToList();
            client.Objectives = item.Objectives.Select(p => _mapper.Map<ObjectiveVM>(p)).ToList();
            resp.Items.Add(client);
        }

        return resp;
    }

Tôi hơi mất hứng đặc biệt là vì nó hoạt động khi tôi chạy cục bộ, nhưng khi tôi triển khai lên máy chủ dàn của mình (IIS 8.5), nó khiến tôi gặp lỗi này và nó hoạt động bình thường. Lỗi bắt đầu xuất hiện sau khi tôi tăng chiều dài tối đa của một trong các mô hình của mình. Tôi cũng đã cập nhật độ dài tối đa của Chế độ xem tương ứng. Và có nhiều phương pháp danh sách khác rất giống nhau và chúng đang hoạt động.

Tôi đã có một công việc Hangfire đang chạy, nhưng công việc này không sử dụng cùng một thực thể. Đó là tất cả những gì tôi có thể nghĩ là có liên quan. Bất kỳ ý tưởng về những gì có thể gây ra điều này?


1
Kiểm tra cái này .
Berkay

2
@Berkay Tôi đã thấy câu hỏi đó và nhiều câu hỏi tương tự khác và đã thử chúng. Phương pháp của tôi không đồng bộ và tôi đã đồng bộ hóa nó để tránh những vấn đề này. Tôi cũng cố gắng loại bỏ ánh xạ, cũng đã cố gắng loại bỏ .ToPagedList nó vẫn tiếp tục gây ra lỗi.
André Luiz

Sẽ rất tốt khi thấy một dấu vết ngăn xếp đầy đủ
Evk

Và để biết liệu nhiều kết quả đang hoạt động có được bật hay không
Jay

Gặp phải vấn đề tương tự, tôi phát hiện ra rằng tôi có các số nguyên có giá trị rỗng trong bảng cơ sở dữ liệu của mình. ngay sau khi tôi đặt các thuộc tính mô hình thực thể của mình để khớp với int nullable, tất cả bắt đầu hoạt động, các thông báo đã gây hiểu lầm cho tôi ...!
AlwaysLearning

Câu trả lời:


88

Tôi không chắc liệu bạn có đang sử dụng IoC và Dependency Injection để giải quyết DbContext của mình hay không. Nếu bạn làm vậy và bạn đang sử dụng IoC gốc từ .NET Core (hoặc bất kỳ IoC-Container nào khác) và bạn đang gặp lỗi này, hãy đảm bảo đăng ký DbContext của bạn dưới dạng Tạm thời. Làm

services.AddTransient<MyContext>();

HOẶC LÀ

services.AddDbContext<MyContext>(ServiceLifetime.Transient);

thay vì

services.AddDbContext<MyContext>();

AddDbContext thêm ngữ cảnh dưới dạng phạm vi, điều này có thể gây ra sự cố khi làm việc với nhiều luồng.

Ngoài ra, các hoạt động async / await có thể gây ra hành vi này, khi sử dụng các biểu thức lambda không đồng bộ.

Thêm nó dưới dạng tạm thời cũng có mặt trái của nó. Bạn sẽ không thể thực hiện thay đổi đối với một số thực thể trên nhiều lớp đang sử dụng ngữ cảnh vì mỗi lớp sẽ nhận được phiên bản DbContext của riêng nó.

Giải thích đơn giản cho điều đó là việc DbContexttriển khai không an toàn theo luồng. Bạn có thể đọc thêm về điều này ở đây


2
Khi tôi sử dụng tạm thời, tôi gặp phải các lỗi kết nối sau (đã đóng hoặc đã xử lý) 'OmniService.DataAccess.Models.OmniServiceDbContext'. System.ObjectDisposedException: Không thể truy cập một đối tượng đã xử lý. Nguyên nhân phổ biến của lỗi này là loại bỏ một ngữ cảnh đã được giải quyết từ việc tiêm phụ thuộc và sau đó cố gắng sử dụng cùng một phiên bản ngữ cảnh ở nơi khác trong ứng dụng của bạn. Điều này có thể xảy ra nếu bạn đang gọi Dispose () trên ngữ cảnh hoặc gói ngữ cảnh trong một câu lệnh using. ... Tên đối tượng: 'AsyncDisposer'.
David

3
Xin chào @David! Tôi đoán bạn đang sử dụng Task.Run(async () => context.Set...)mà không cần chờ nó hoặc tạo bối cảnh db có phạm vi mà không cần chờ kết quả. Điều này có nghĩa là ngữ cảnh của bạn có thể đã được xử lý khi truy cập nó. Nếu bạn đang sử dụng Microsoft DI, bạn phải tự tạo phạm vi phụ thuộc trong phạm vi đó Task.Run. Kiểm tra các liên kết này. stackoverflow.com/questions/45047877/… docs.microsoft.com/en-us/dotnet/api/…
alsami

3
Như đã chỉ ra trước đó, nếu bạn lỡ gọi một phương thức không đồng bộ với từ khóa await, bạn sẽ gặp phải vấn đề này.
Yennefer

1
Điều này có thể ổn, nhưng người ta phải suy nghĩ kỹ hơn về thời gian tồn tại và phạm vi phân giải mong muốn của quyền truy cập dữ liệu hơn là sử dụng một cách ung dung nhất thời mà không có sắc thái của hoàn cảnh. Trên thực tế, tôi cho rằng hiếm khi người ta muốn một ngữ cảnh dữ liệu chỉ là tạm thời. Nếu phạm vi của một đơn vị công việc là một cái gì đó liên quan đến nhiều hơn một hoạt động dữ liệu đơn lẻ, thì phạm vi giao dịch nên trải dài hơn thế. Độ phân giải của bối cảnh dữ liệu của bạn phải phản ánh phạm vi đơn vị công việc của bạn. Đây là điều cần được suy nghĩ kỹ lưỡng và đây không phải là câu trả lời phù hợp cho tất cả.
Dave Rael

3
@alsami bạn là anh hùng của tôi. 6 giờ gỡ lỗi đau đớn. Đây là giải pháp. Nếu ai đó đang tiêm IHttpContextAccessor vào DbContext và Yêu cầu bồi thường là rỗng, đây là giải pháp. Cảm ơn rất nhiều chàng trai.
jcmontx

56

Trong một số trường hợp, lỗi này xảy ra khi gọi một async phương pháp mà không có awaittừ khóa, mà chỉ đơn giản có thể được giải quyết bằng cách thêm awaittrước khi gọi phương thức. tuy nhiên, câu trả lời có thể không liên quan đến câu hỏi đã đề cập nhưng nó có thể giúp giải quyết một lỗi tương tự.


4
Điều này đã xảy ra với tôi. Đang thay đổi First()thành await / FirstAsync()đã hoạt động.
Guilherme

Ủng hộ. Cũng xem jimlynn.wordpress.com/2017/11/16/… Jim Lynn "LỖI KHUNG TOÀN BỘ: VẬN HÀNH THỨ HAI ĐƯỢC BẮT ĐẦU TRÊN BỐI CẢNH NÀY TRƯỚC KHI HOÀN THÀNH HOẠT ĐỘNG TRƯỚC. BẤT KỲ THÀNH VIÊN NÀO CŨNG KHÔNG ĐƯỢC ĐẢM BẢO LÀ AN TOÀN."
granadaCoder

Cám ơn vì cái này! Đây chính xác là vấn đề của tôi ... Quên thêm thời gian chờ trên mdethod không đồng bộ.
AxleWack

Cũng xảy ra với tôi, và nhận xét này đã giúp ích khi tôi tìm kiếm nơi mà tôi quên mất một điều đang chờ đợi. Khi tôi tìm thấy nó, vấn đề đã được giải quyết.
Zion Hai

42

Ngoại lệ có nghĩa _contextlà đang được sử dụng bởi hai luồng cùng một lúc; hoặc hai luồng trong cùng một yêu cầu hoặc bởi hai yêu cầu.

Có thể _contextkhai báo tĩnh không? Nó không nên.

Hay bạn đang gọi GetClientsnhiều lần trong cùng một yêu cầu từ một nơi khác trong mã của bạn?

Bạn có thể đã làm điều này, nhưng lý tưởng nhất là bạn đang sử dụng phụ thuộc chèn cho của bạn DbContext, có nghĩa là bạn sẽ sử dụng AddDbContext()trong Startup.cs của mình và hàm tạo bộ điều khiển của bạn sẽ trông giống như sau:

private readonly MyDbContext _context; //not static

public MyController(MyDbContext context) {
    _context = context;
}

Nếu mã của bạn không giống như thế này, hãy cho chúng tôi xem và có thể chúng tôi có thể trợ giúp thêm.


1
Có lẽ đó là công việc tôi có. Tôi đã quản lý để giải quyết, hãy xem câu trả lời của tôi. Nhưng tôi đang đánh dấu bạn là người phù hợp
André Luiz

Mã của tôi chính xác như thế này và chúng tôi thường theo dõi "Thao tác thứ hai bắt đầu trên ngữ cảnh này trước khi hoàn thành thao tác không đồng bộ trước đó. Sử dụng 'await' để đảm bảo rằng mọi thao tác không đồng bộ đã hoàn thành trước khi gọi một phương thức khác trên ngữ cảnh này. Bất kỳ thành viên trường hợp nào không được đảm bảo an toàn cho luồng. - tại System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered () ".
NMathur

@NMathur Bạn có đang sử dụng _contextđối tượng của mình trong các chuỗi khác không? Như bên trong một Task.Run()ví dụ?
Gabriel Luci

@GabrielLuci tất cả các phương thức của tôi đều không đồng bộ như bên dưới, điều này có gây ra sự cố không. Kiến thức của tôi về chủ đề này là rất ít. Bạn có thể gợi ý tôi nên đọc chi tiết ở đâu và những gì để hiểu những hành vi này không? public async Task <List <Item>> GetItems (int orderId) {List <Item> items = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); trả lại hàng; }
NMathur

@NMathur Có vẻ ổn. Chỉ cần đảm bảo rằng bạn luôn sử dụng awaitvới các phương thức không đồng bộ. Nếu bạn không sử dụng await, bạn có thể vô tình mắc vào đa luồng.
Gabriel Luci

8
  • Giải quyết vấn đề của tôi bằng cách sử dụng dòng mã này trong tệp Startup.cs của tôi.
    Thêm một dịch vụ tạm thời có nghĩa là mỗi khi dịch vụ được yêu cầu, một phiên bản mới sẽ được tạo khi bạn đang làm việc với Dependency injection

           services.AddDbContext<Context>(options =>
                            options.UseSqlServer(_configuration.GetConnectionString("ContextConn")),
                 ServiceLifetime.Transient);
    

8

Tôi đã gặp vấn đề tương tự và hóa ra dịch vụ dành cho cha mẹ là một singelton. Vì vậy, ngữ cảnh cũng tự động trở thành singelton. Mặc dù đã được tuyên bố là Per Life Time Scoped in DI.

Tiêm dịch vụ có thời gian sống khác nhau vào một dịch vụ khác

  1. Không bao giờ đưa các dịch vụ Phạm vi & Tạm thời vào dịch vụ Singleton. (Điều này có hiệu quả chuyển đổi dịch vụ tạm thời hoặc theo phạm vi thành singleton.)

  2. Không bao giờ đưa các dịch vụ tạm thời vào dịch vụ có phạm vi (Điều này chuyển đổi dịch vụ tạm thời thành dịch vụ có phạm vi.)


đây chính xác là vấn đề của tôi
Jonesopolis

Đây cũng là vấn đề của tôi. Tôi đã đăng ký một lớp xử lý dưới dạng singleton và DbContext dưới dạng tạm thời. Tôi đã phải sử dụng ServiceProvider trong lớp Handler để lấy một phiên bản tạm thời từ vùng chứa DI mỗi khi Handler bị tấn công
Daiana Sodré

5

Tôi đã có những lỗi giống nhau. Nó xảy ra bởi vì tôi đã gọi một phương thức được xây dựng public async void ...thay vì public async Task ....


4

Tôi nghĩ rằng câu trả lời này vẫn có thể giúp một số người và tiết kiệm nhiều lần. Tôi đã giải quyết một vấn đề tương tự bằng cách thay đổi IQueryablethành List(hoặc thành mảng, bộ sưu tập ...).

Ví dụ:

var list=_context.table1.where(...);

đến

var list=_context.table1.where(...).ToList(); //or ToArray()...

2
IMHO, Câu trả lời này không đáng bị trừ điểm, Nó chỉ là diễn đạt kém. .ToList () thực sự giải quyết được phần lớn các vấn đề "hoạt động thứ hai ..." do thực tế là nó buộc đánh giá ngay lập tức biểu thức. Bằng cách này không có hoạt động ngữ cảnh xếp hàng.
vassilag

Đây là vấn đề trong trường hợp của tôi. Tôi đã có xxx.Contains (z.prop) trong mệnh đề where của một truy vấn. xxx được cho là một mảng int [] riêng biệt được giải quyết từ một truy vấn trước đó. Thật không may, vào thời điểm truy vấn thứ hai xuất hiện, xxx vẫn là một IQueryable. Thêm xxx.ToArray () trước truy vấn thứ hai đã khắc phục sự cố của tôi.
Jason Butera

2

Tôi gặp phải vấn đề tương tự nhưng không có lý do nào trong số những vấn đề được liệt kê ở trên. Tôi đã tạo một tác vụ, tạo một phạm vi bên trong tác vụ và yêu cầu vùng chứa tải một dịch vụ. Điều đó hoạt động tốt nhưng sau đó tôi sử dụng dịch vụ thứ hai bên trong tác vụ và tôi quên yêu cầu nó ở phạm vi mới. Do đó, dịch vụ thứ 2 đang sử dụng DbContext đã được xử lý.

Task task = Task.Run(() =>
    {
        using (var scope = serviceScopeFactory.CreateScope())
        {
            var otherOfferService = scope.ServiceProvider.GetService<IOfferService>();
            // everything was ok here. then I did: 
            productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed.
            ...
        }
    }

Tôi nên làm điều này:

var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();

Không phải ngữ cảnh sẽ chỉ được hiển thị khi mọi thứ trong khối using đã hoàn tất quá trình thực thi?
Sello Mkantjwa

Khi hành động được xử lý, mọi thứ sẽ được xử lý trong phạm vi đó. Nếu bạn có một tác vụ đang chạy trong nền và tác vụ đó dài hơn hành động đó, bạn sẽ gặp sự cố này trừ khi bạn tạo một phạm vi mới cho tác vụ, giống như tôi đã làm trong ví dụ. Mặt khác, nếu nhiệm vụ của bạn có thể mất nhiều thời gian hoặc bạn muốn chắc chắn 100% rằng nó sẽ chạy, bạn có thể cần sử dụng hàng đợi. Nếu bạn đang sử dụng Azure, bạn có thể sử dụng hàng đợi Xe buýt Dịch vụ.
Francisco Goldenstein

2

Tình huống của tôi khác: Tôi đang cố gắng tạo cơ sở dữ liệu với 30 người dùng, thuộc các vai trò cụ thể, vì vậy tôi đang chạy mã này:

for (var i = 1; i <= 30; i++)
{
    CreateUserWithRole("Analyst", $"analyst{i}", UserManager);
}

Đây là một chức năng Đồng bộ hóa. Trong số đó, tôi có 3 cuộc gọi tới:

UserManager.FindByNameAsync(username).Result
UserManager.CreateAsync(user, pass).Result
UserManager.AddToRoleAsync(user, roleName).Result

Khi tôi thay thế .Resultbằng .GetAwaiter().GetResult(), lỗi này đã biến mất.


2

Entity Framework Core không hỗ trợ nhiều hoạt động song song đang được chạy trên cùng một DbContextphiên bản. Điều này bao gồm cả việc thực hiện song song các asynctruy vấn và bất kỳ việc sử dụng đồng thời rõ ràng nào từ nhiều luồng. Do đó, hãy luôn await asyncgọi ngay lập tức hoặc sử dụng các DbContextphiên bản riêng biệt cho các hoạt động thực thi song song.


0

Tôi nhận được cùng một tin nhắn. Nhưng nó không có ý nghĩa gì trong trường hợp của tôi. Vấn đề của tôi là tôi đã sử dụng thuộc tính "NotMapped" do nhầm lẫn. Nó có thể chỉ có nghĩa là lỗi cú pháp Linq hoặc lớp mô hình trong một số trường hợp. Thông báo lỗi có vẻ gây hiểu lầm. Ý nghĩa ban đầu của thông báo này là bạn không thể gọi async trên cùng một dbcontext nhiều hơn một lần trong cùng một yêu cầu.

[NotMapped]
public int PostId { get; set; }
public virtual Post Post { get; set; }

Bạn có thể kiểm tra liên kết này để biết chi tiết, https://www.softwareblogs.com/Posts/Details/5/error-a-second-operation-started-on-this-context-before-a-previous-operation-completed


0

Tôi có một dịch vụ nền thực hiện một hành động cho mỗi mục nhập trong bảng. Vấn đề là nếu tôi lặp lại và sửa đổi một số dữ liệu trên cùng một phiên bản của DbContext thì lỗi này sẽ xảy ra.

Một giải pháp, như đã đề cập trong chủ đề này là thay đổi thời gian tồn tại của DbContext thành tạm thời bằng cách định nghĩa nó như

services.AddDbContext<DbContext>(ServiceLifetime.Transient);

nhưng vì tôi thực hiện các thay đổi trong nhiều dịch vụ khác nhau và cam kết chúng cùng một lúc bằng cách sử dụng SaveChanges()phương pháp nên giải pháp này không hoạt động trong trường hợp của tôi.

Vì mã của tôi chạy trong một dịch vụ, tôi đã làm điều gì đó như

using (var scope = Services.CreateScope())
{
   var entities = scope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = scope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

để có thể sử dụng dịch vụ như thể đó là một yêu cầu đơn giản. Vì vậy, để giải quyết vấn đề, tôi chỉ cần chia phạm vi đơn lẻ thành hai, một cho truy vấn và một cho các hoạt động ghi như sau:

using (var readScope = Services.CreateScope())
using (var writeScope = Services.CreateScope())
{
   var entities = readScope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = writeScope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

Như vậy, thực tế có hai trường hợp DbContext khác nhau đang được sử dụng.

Một giải pháp khả thi khác là đảm bảo rằng thao tác đọc đã kết thúc trước khi bắt đầu lặp lại. Điều đó không thực tế lắm trong trường hợp của tôi vì có thể có rất nhiều kết quả cần được tải vào bộ nhớ cho thao tác mà tôi đã cố gắng tránh bằng cách sử dụng Queryable ngay từ đầu.


0

Tôi đã quản lý để gặp lỗi đó bằng cách chuyển IQueryablemột phương thức vào một phương thức sau đó sử dụng 'danh sách' IQueryable đó như một phần của một truy vấn khác cho cùng ngữ cảnh.

public void FirstMethod()
{
    // This is returning an IQueryable
    var stockItems = _dbContext.StockItems
        .Where(st => st.IsSomething);

    SecondMethod(stockItems);
}

public void SecondMethod(IEnumerable<Stock> stockItems)
{
    var grnTrans = _dbContext.InvoiceLines
        .Where(il => stockItems.Contains(il.StockItem))
        .ToList();
}

Để ngăn điều đó xảy ra, tôi đã sử dụng cách tiếp cận ở đây và hiện thực hóa danh sách đó trước khi chuyển nó sang phương pháp thứ hai, bằng cách thay đổi lời gọi SecondMethodthànhSecondMethod(stockItems.ToList()


Điều này đã giải quyết được vấn đề, nhưng điều này sẽ không làm chậm hiệu suất, Có giải pháp thay thế nào không?
Dheeraj Kumar

0

Đầu tiên, hãy ủng hộ (ít nhất) câu trả lời của alsami. Điều đó đã giúp tôi đi đúng đường.

Nhưng đối với những người bạn đang làm IoC, đây là một chút tìm hiểu sâu hơn.

Lỗi của tôi (giống như những người khác)

Một hoặc nhiều lỗi đã xảy ra. (Thao tác thứ hai bắt đầu trên ngữ cảnh này trước khi thao tác trước đó hoàn tất. Điều này thường do các luồng khác nhau sử dụng cùng một phiên bản của DbContext gây ra. Để biết thêm thông tin về cách tránh các sự cố về luồng với DbContext, hãy xem https://go.microsoft.com / fwlink /? linkid = 2097913. )

Thiết lập mã của tôi. "Chỉ những điều căn bản"...

public class MyCoolDbContext: DbContext{
    public DbSet <MySpecialObject> MySpecialObjects {        get;        set;    }
}

public interface IMySpecialObjectDomainData{}

và (lưu ý MyCoolDbContext đang được đưa vào)

public class MySpecialObjectEntityFrameworkDomainDataLayer: IMySpecialObjectDomainData{
    public MySpecialObjectEntityFrameworkDomainDataLayer(MyCoolDbContext context) {
        /* HERE IS WHERE TO SET THE BREAK POINT, HOW MANY TIMES IS THIS RUNNING??? */
        this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
    }
}

public interface IMySpecialObjectManager{}

public class MySpecialObjectManager: IMySpecialObjectManager
{
    public const string ErrorMessageIMySpecialObjectDomainDataIsNull = "IMySpecialObjectDomainData is null";
    private readonly IMySpecialObjectDomainData mySpecialObjectDomainData;

    public MySpecialObjectManager(IMySpecialObjectDomainData mySpecialObjectDomainData) {
        this.mySpecialObjectDomainData = mySpecialObjectDomainData ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectDomainDataIsNull, (Exception)null);
    }
}

Và cuối cùng, lớp đa luồng của tôi, được gọi từ Ứng dụng điều khiển (ứng dụng Giao diện dòng lệnh)

    public interface IMySpecialObjectThatSpawnsThreads{}

public class MySpecialObjectThatSpawnsThreads: IMySpecialObjectThatSpawnsThreads
{
    public const string ErrorMessageIMySpecialObjectManagerIsNull = "IMySpecialObjectManager is null";

    private readonly IMySpecialObjectManager mySpecialObjectManager;

    public MySpecialObjectThatSpawnsThreads(IMySpecialObjectManager mySpecialObjectManager) {
        this.mySpecialObjectManager = mySpecialObjectManager ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectManagerIsNull, (Exception)null);
    }
}

và tích lũy DI. (Một lần nữa, điều này dành cho ứng dụng bảng điều khiển (giao diện dòng lệnh) ... thể hiện hành vi hơi khác so với ứng dụng web)

private static IServiceProvider BuildDi(IConfiguration configuration) {
    /* this is being called early inside my command line application ("console application") */

    string defaultConnectionStringValue = string.Empty; /* get this value from configuration */

    ////setup our DI
    IServiceCollection servColl = new ServiceCollection()
        ////.AddLogging(loggingBuilder => loggingBuilder.AddConsole())

        /* THE BELOW TWO ARE THE ONES THAT TRIPPED ME UP.  */
        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

    /* so the "ServiceLifetime.Transient" below................is what you will find most commonly on the internet search results */
     # if (MY_ORACLE)
        .AddDbContext<ProvisioningDbContext>(options => options.UseOracle(defaultConnectionStringValue), ServiceLifetime.Transient);
     # endif

     # if (MY_SQL_SERVER)
        .AddDbContext<ProvisioningDbContext>(options => options.UseSqlServer(defaultConnectionStringValue), ServiceLifetime.Transient);
     # endif

    servColl.AddSingleton <IMySpecialObjectThatSpawnsThreads,        MySpecialObjectThatSpawnsThreads>();

    ServiceProvider servProv = servColl.BuildServiceProvider();

    return servProv;
}

Điều làm tôi ngạc nhiên là (thay đổi thành) tạm thời cho

        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

Lưu ý, tôi nghĩ vì IMySpecialObjectManager đã được đưa vào "MySpecialObjectThatSpawnsThreads", các đối tượng được tiêm đó cần phải là Tạm thời để hoàn thành chuỗi.

Vấn đề là ....... nó không chỉ cần DbContext (Của tôi). Transient ... mà là một phần lớn hơn của DI Graph.

Mẹo gỡ lỗi:

Đường thẳng này:

this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);

Đặt điểm ngắt trình gỡ lỗi của bạn ở đó. Nếu MySpecialObjectThatSpawnsThreads của bạn tạo N số luồng (ví dụ như 10 luồng) ...... và dòng đó chỉ được đánh một lần ... đó là vấn đề của bạn. DbContext của bạn đang vượt qua các chủ đề.

TẶNG KEM:

Tôi khuyên bạn nên đọc url / bài viết này bên dưới (cũ nhưng tốt) về sự khác biệt giữa ứng dụng web và ứng dụng bảng điều khiển

https://mehdi.me/ambient-dbcontext-in-ef6/

Đây là tiêu đề của bài báo trong trường hợp liên kết thay đổi.

QUẢN LÝ DBC THEO CÁCH ĐÚNG VỚI KHUNG CỦA ENTITY 6: HƯỚNG DẪN BÊN TRONG Mehdi El Gueddari

Tôi gặp sự cố này với WorkFlowCore https://github.com/danielgerlag/workflow-core

  <ItemGroup>
    <PackageReference Include="WorkflowCore" Version="3.1.5" />
  </ItemGroup>

mã mẫu bên dưới .. để giúp những người tìm kiếm trên internet trong tương lai

 namespace MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Workflows
    {
        using System;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Constants;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Glue;
        using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.WorkflowSteps;

        using WorkflowCore.Interface;
        using WorkflowCore.Models;

        public class MySpecialObjectInterviewDefaultWorkflow : IWorkflow<MySpecialObjectInterviewPassThroughData>
        {
            public const string WorkFlowId = "MySpecialObjectInterviewWorkflowId";

            public const int WorkFlowVersion = 1;

            public string Id => WorkFlowId;

            public int Version => WorkFlowVersion;

            public void Build(IWorkflowBuilder<MySpecialObjectInterviewPassThroughData> builder)
            {
                builder
                             .StartWith(context =>
                    {
                        Console.WriteLine("Starting workflow...");
                        return ExecutionResult.Next();
                    })

                        /* bunch of other Steps here that were using IMySpecialObjectManager.. here is where my DbContext was getting cross-threaded */


                    .Then(lastContext =>
                    {
                        Console.WriteLine();

                        bool wroteConcreteMsg = false;
                        if (null != lastContext && null != lastContext.Workflow && null != lastContext.Workflow.Data)
                        {
                            MySpecialObjectInterviewPassThroughData castItem = lastContext.Workflow.Data as MySpecialObjectInterviewPassThroughData;
                            if (null != castItem)
                            {
                                Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete :)  {0}   -> {1}", castItem.PropertyOne, castItem.PropertyTwo);
                                wroteConcreteMsg = true;
                            }
                        }

                        if (!wroteConcreteMsg)
                        {
                            Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete (.Data did not cast)");
                        }

                        return ExecutionResult.Next();
                    }))

                    .OnError(WorkflowCore.Models.WorkflowErrorHandling.Retry, TimeSpan.FromSeconds(60));

            }
        }
    }

ICollection<string> workFlowGeneratedIds = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                    MySpecialObjectInterviewPassThroughData currentMySpecialObjectInterviewPassThroughData = new MySpecialObjectInterviewPassThroughData();
                    currentMySpecialObjectInterviewPassThroughData.MySpecialObjectInterviewPassThroughDataSurrogateKey = i;

                    ////  private readonly IWorkflowHost workflowHost;
                    string wfid = await this.workflowHost.StartWorkflow(MySpecialObjectInterviewDefaultWorkflow.WorkFlowId, MySpecialObjectInterviewDefaultWorkflow.WorkFlowVersion, currentMySpecialObjectInterviewPassThroughData);
                    workFlowGeneratedIds.Add(wfid);
                }

0

Trong trường hợp của tôi, tôi sử dụng một thành phần mẫu trong Blazor.

 <BTable ID="Table1" TotalRows="MyList.Count()">

Sự cố đang gọi một phương thức (Đếm) trong tiêu đề thành phần. Để giải quyết vấn đề, tôi đã thay đổi nó như thế này:

int total = MyList.Count();

và sau đó :

<BTable ID="Table1" TotalRows="total">

0

Tôi biết vấn đề này đã được hỏi cách đây hai năm, nhưng tôi vừa gặp sự cố này và bản sửa lỗi tôi đã sử dụng thực sự hữu ích.

Nếu bạn đang thực hiện hai truy vấn với cùng một Ngữ cảnh - bạn có thể cần phải xóa AsNoTracking. Nếu bạn sử dụng, AsNoTrackingbạn đang tạo một trình đọc dữ liệu mới cho mỗi lần đọc. Hai bộ đọc dữ liệu không thể đọc cùng một dữ liệu.


0

Trong trường hợp của tôi, tôi đang sử dụng một khóa không cho phép sử dụng await và không tạo cảnh báo trình biên dịch khi bạn không chờ đợi một async.

Vấn đề:

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync();
}

// some other code somewhere else doing await context.SaveChangesAsync() shortly after the lock gets the concurrency error

Cách khắc phục: Chờ cho không đồng bộ bên trong khóa bằng cách chặn nó bằng .Wait ()

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync().Wait();
}

0

Một trường hợp khác có thể xảy ra: nếu bạn sử dụng kết nối trực tiếp, đừng quên đóng nếu. Tôi cần thực hiện truy vấn SQL tùy ý và đọc kết quả. Đây là một bản sửa lỗi nhanh, tôi không muốn xác định lớp dữ liệu, không thiết lập kết nối SQL "bình thường". Vì vậy, đơn giản là tôi đã sử dụng lại kết nối cơ sở dữ liệu của EFC như var connection = Context.Database.GetDbConnection() as SqlConnection. Hãy chắc chắn rằng bạn đã gọi connection.Close()trước khi thực hiện Context.SaveChanges().


-1

Tôi gặp sự cố tương tự khi cố gắng sử dụng FirstOrDefaultAsync() phương thức không đồng bộ trong đoạn mã bên dưới. Và khi tôi sửa FirstOrDefault()- vấn đề đã được giải quyết!

_context.Issues.Add(issue);
        await _context.SaveChangesAsync();

        int userId = _context.Users
            .Where(u => u.UserName == Options.UserName)
            .FirstOrDefaultAsync()
            .Id;
...

1
Nó hoàn toàn không liên quan đến FirstOrDefault () hoặc FirstOrDefaultAsync () mà là về cách sử dụng dbContext.
sajadre

-2

Nếu phương thức của bạn đang trả lại một cái gì đó, bạn có thể giải quyết lỗi này bằng cách đặt .Resultvào cuối công việc và .Wait()nếu nó không trả lại bất kỳ thứ gì.


-6

Tôi chỉ cố gắng làm cho nó hoạt động trở lại. Nó không có nhiều ý nghĩa nhưng nó đã hoạt động:

  1. Xóa Hangfire khỏi StartUp (Tôi đang tạo công việc của mình ở đó)
  2. Đã xóa cơ sở dữ liệu hangfire
  3. Đã khởi động lại máy chủ

Tôi sẽ điều tra thêm sau nhưng phương thức tôi đã gọi bằng hangfire nhận được DBContext và đó là nguyên nhân có thể xảy ra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.