using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using StopShopping.EF; using StopShopping.Services.Models.Req; using StopShopping.Services.Models.Resp; using O = StopShopping.OpenPlatform; namespace StopShopping.Services.Implementions; public class DistrictService : IDistrictService { public DistrictService( StopShoppingContext dbContext, O.IDistrictService districtService, ILogger logger) { _dbContext = dbContext; _oDistrictService = districtService; _logger = logger; } private readonly StopShoppingContext _dbContext; private readonly O.IDistrictService _oDistrictService; private readonly ILogger _logger; public async Task InitialDatabaseAsync(CancellationToken cancellationToken) { _logger.LogInformation("开始初始化行政区划"); if (await _dbContext.Districts.AnyAsync(cancellationToken)) { _logger.LogInformation("已经存在数据,无需初始化"); } else { var districtsResp = await _oDistrictService.GetTop3LevelDistrictsAsync(cancellationToken); if (districtsResp?.IsSucced ?? false) { if (null != districtsResp?.Districts) { using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken); short order = 1; int parentId = 0; var districtsProvince = districtsResp.Districts .Select(d => Cast(d, parentId, order++)) .ToList(); await _dbContext.Districts.AddRangeAsync(districtsProvince, cancellationToken); await _dbContext.SaveChangesAsync(cancellationToken); foreach (var province in districtsResp.Districts) { parentId = districtsProvince.First(p => p.Code == province.Code).Id; order = 1; var citys = province.Districts; if (null == citys) { await transaction.RollbackAsync(cancellationToken); _logger.LogError("行政区划下级数据不完整:{Name}", province.Name); return; } var districtsCity = citys .Select(d => Cast(d, parentId, order++)) .ToList(); await _dbContext.Districts.AddRangeAsync(districtsCity, cancellationToken); await _dbContext.SaveChangesAsync(cancellationToken); // 直辖市下属区 // var directlyCitysDistrict = citys // .Where(d => d.Districts?.Count == 0) // .ToList(); // if (0 == directlyCitysDistrict.Count) // { // await transaction.RollbackAsync(cancellationToken); // _logger.LogError("行政区划数据不完整,缺少直辖市数据"); // return; // } var semaphoreSlim = new SemaphoreSlim(50); //(parent id, district response) List> districtTasks = []; foreach (var city in citys) { parentId = districtsCity.First(c => c.Code == city.Code).Id; order = 1; if (city.Districts == null || city.Districts.Count == 0)//直辖市 { try { await semaphoreSlim.WaitAsync(cancellationToken); districtTasks.Add( Task.FromResult(( parentId , await _oDistrictService.GetChildrenAsync(city.Code, cancellationToken))) ); } finally { semaphoreSlim.Release(); } } else { var districtsDistrict = city.Districts .Select(d => Cast(d, parentId, order++)) .ToList(); await _dbContext.Districts.AddRangeAsync(districtsDistrict, cancellationToken); await _dbContext.SaveChangesAsync(cancellationToken); var districtTask = city.Districts!.Select(async (d) => { try { await semaphoreSlim.WaitAsync(); return ( districtsDistrict.First(dd => dd.Code == d.Code).Id , await _oDistrictService.GetChildrenAsync(d.Code, cancellationToken) ); } finally { semaphoreSlim.Release(); } }); districtTasks.AddRange(districtTask); } } var streets = await Task.WhenAll(districtTasks); foreach (var s in streets) { order = 1; parentId = s.Item1; if (s.Item2?.IsSucced ?? false) { var districtsStreet = s.Item2.Districts ?.Select(ds => Cast(ds, parentId, order++)) .ToList(); if (null != districtsStreet) { await _dbContext.Districts.AddRangeAsync(districtsStreet, cancellationToken); await _dbContext.SaveChangesAsync(cancellationToken); } } else { await transaction.RollbackAsync(cancellationToken); _logger.LogError("街道数据请求失败:{Message}", s.Item2?.Message); return; } } } await transaction.CommitAsync(cancellationToken); } } else { _logger.LogError("行政区划接口错误:{Message}", districtsResp?.Message); } } _logger.LogInformation("结束初始化行政区划"); } public async Task>> GetTop3LevelDistrictsAsync() { List districts = []; var top3Districts = await _dbContext.Districts .Where(d => d.Level <= 3) .AsNoTracking() .ToListAsync(); if (0 != top3Districts.Count) { Dictionary idDicts = []; foreach (var dbDistrict in top3Districts) { idDicts.Add(dbDistrict.Id, Cast(dbDistrict)); } foreach (var kv in idDicts) { if (kv.Value.ParentId > 0) idDicts[kv.Value.ParentId].Children.Add(kv.Value); else districts.Add(kv.Value); } } var result = new ApiResponse>(districts); return result; } public ApiResponse> GetChildren(DistrictParentIdParams model) { var children = _dbContext.Districts .Where(d => d.ParentId == model.ParentId) .AsNoTracking() .Select(Cast) .ToList(); return new ApiResponse>(children); } private District Cast(EF.Models.District district) { return new District { Children = [], FullName = district.FullName, Id = district.Id, Level = district.Level, ParentId = district.ParentId }; } private EF.Models.District Cast(O.DistrictResponse.District district, int parentId, short order) { return new EF.Models.District { Code = district.Code, FullName = district.FullName, Latitude = district.Latitude.ToString(), Level = (short)(district.Level ?? 0), Longitude = district.Longitude.ToString(), Name = district.Name, Order = order, ParentId = parentId, Pinyin = district.PinYin ?? "" }; } }