Files
2026-03-25 14:55:34 +08:00

240 lines
9.4 KiB
C#

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<DistrictService> logger)
{
_dbContext = dbContext;
_oDistrictService = districtService;
_logger = logger;
}
private readonly StopShoppingContext _dbContext;
private readonly O.IDistrictService _oDistrictService;
private readonly ILogger<DistrictService> _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<Task<(int, O.DistrictResponse?)>> 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<ApiResponse<List<District>>> GetTop3LevelDistrictsAsync()
{
List<District> districts = [];
var top3Districts = await _dbContext.Districts
.Where(d => d.Level <= 3)
.AsNoTracking()
.ToListAsync();
if (0 != top3Districts.Count)
{
Dictionary<int, District> 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<List<District>>(districts);
return result;
}
public ApiResponse<List<District>> GetChildren(DistrictParentIdParams model)
{
var children = _dbContext.Districts
.Where(d => d.ParentId == model.ParentId)
.AsNoTracking()
.Select(Cast)
.ToList();
return new ApiResponse<List<District>>(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 ?? ""
};
}
}