این متد من اه هنگام اضافه کردن یک محصول به سبد خرید خودم. تقریبا همه چیزش درست اه به جز یه موضوع و اون اینکه وقتی کاربر مهمان هستی و یک محصول را به سبد خرید اضافه می کنه یه کاربر روی گوشیش اگر یک نفر دیگه روی یک دستگاه دیگه وارد می شه اون محصول روی سبد خریدش اضافه شده. البته این موضوع همیشگی نیست و اینکه دقیقا هم به صورتی که گفتم پیش نمی یاد چون بعضی مواقع این موضوع رو چک کردم و مشکلی ندیدم هر از گاهی روی سیستم ام می بینم و دلیل اصلی شو پیدا نکردم. [UnitOfWork] public async Task AddItemAsync(AddCartInput input) { if (input == null) throw new ArgumentNullException(nameof(input)); var cart = await _cartService.GetOrCreateCartAsync(); if (input.Quantity <= 0) input.Quantity = 1; // مطمئن شو Items لود شده‌اند (GetOrCreateCartAsync آنها را Include می‌کند) var existingItem = cart.Items.FirstOrDefault(x => x.VariantId == input.VariantId); if (existingItem != null) { existingItem.Quantity += input.Quantity ?? 1; await _cartItemRepository.UpdateAsync(existingItem); } else { var variant = await _variantRepository.GetAll().AsNoTracking().FirstOrDefaultAsync(x => x.Id == input.VariantId); if (variant == null) throw new UserFriendlyException("محصول مورد نظر یافت نشد."); var item = new CartItem { CartId = cart.Id, VariantId = input.VariantId, Quantity = input.Quantity ?? 1, UnitPrice = variant.NetPrice, StrikePrice = variant.RegularPrice, //UnitDiscountAmount = variant.RegularPrice - variant.SalePrice }; await _cartItemRepository.InsertAsync(item); // دقت: چون cart tracked است، اگر بخواهی می‌توانی item را به cart.Items اضافه کنی: // cart.Items.Add(item); } await UnitOfWorkManager.Current.SaveChangesAsync(); var updated = await GetCartReadOnlyAsync(cart.Key); return ObjectMapper.Map(updated); } public async Task GetOrCreateCartAsync() { long? userId = _nextSession.UserId; var deviceId = GetDeviceIdFromRequest(); Cart cart; // اگر کاربر لاگین شده و deviceId وجود دارد → چک برای merge if (userId != null && !string.IsNullOrEmpty(deviceId)) { await MergeCartOnLoginAsync(userId.Value, deviceId); // await CurrentUnitOfWork.SaveChangesAsync(); } //using (var unitOfWork = UnitOfWorkManager.Begin(System.Transactions.TransactionScopeOption.RequiresNew)) { if (userId != null) { cart = _cartRepository.GetAll() .AsNoTracking() .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.VariantAttributeValues).ThenInclude(x => x.AttributeValue).AsSplitQuery() .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.Product) .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.Tags).ThenInclude(x => x.Tag) .FirstOrDefault(x => x.UserId == userId); } else { if (string.IsNullOrEmpty(deviceId)) deviceId = GenerateDeviceId(); cart = _cartRepository.GetAll() .AsNoTracking() .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.VariantAttributeValues).ThenInclude(x => x.AttributeValue).AsSplitQuery() .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.Product) .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.Tags).ThenInclude(x => x.Tag) .FirstOrDefault(x => x.DeviceId == deviceId); } if (cart == null) { cart = new Cart { UserId = userId, DeviceId = userId == null ? deviceId : null }; _cartRepository.Insert(cart); // لازم است تا id/key اختصاص یابد قبل از استفاده UnitOfWorkManager.Current.SaveChanges(); cart = _cartRepository.GetAll() .AsNoTracking() .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.VariantAttributeValues).ThenInclude(x => x.AttributeValue).AsSplitQuery() .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.Product) .Include(x => x.Items).ThenInclude(x => x.Variant).ThenInclude(x => x.Tags).ThenInclude(x => x.Tag) .FirstOrDefault(x => x.UserId == userId); } //unitOfWork.Complete(); } return cart; } public void MergeCartOnLoginAsync(long userId, string deviceId) { try { //using (var unitOfWork = UnitOfWorkManager.Begin(System.Transactions.TransactionScopeOption.RequiresNew)) { if (string.IsNullOrWhiteSpace(deviceId)) return; var guestCart = _cartRepository.GetAll() .Include(x => x.Items) .FirstOrDefault(x => x.DeviceId == deviceId); if (guestCart == null) return; var userCart = _cartRepository.GetAll() .Include(x => x.Items) .FirstOrDefault(x => x.UserId == userId); // اگر سبد کاربر وجود نداشت → فقط مالکیت را عوض کن if (userCart == null) { guestCart.UserId = userId; guestCart.DeviceId = null; } else { foreach (var guestItem in guestCart.Items.ToList()) { var userItem = userCart.Items .FirstOrDefault(x => x.VariantId == guestItem.VariantId); if (userItem != null) { userItem.Quantity += guestItem.Quantity; _cartItemRepository.Delete(guestItem); } else { // 🔥 خیلی مهم — Navigation sync guestItem.CartId = userCart.Id; //guestItem.Cart = userCart; //userCart.Items.Add(guestItem); } } // 🔥 اول آیتم‌ها Save شوند // await CurrentUnitOfWork.SaveChangesAsync(); CurrentUnitOfWork.SaveChanges(); // // بعد Cart مهمان حذف شود _cartRepository.Delete(guestCart); } //unitOfWork.Complete(); } } catch (Exception ex) { throw; } }