admin/src/Oms.SqlSugarCore/Channels/ServiceChannelRepository.cs
zzh b17e6639a4
All checks were successful
Build and Deploy / deploy (push) Successful in 1m3s
fix: 主数据新增兼容软删唯一键,避免 Duplicate entry
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-05 11:53:08 +08:00

242 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Fake.DependencyInjection;
using Oms.Domain.ChannelsAggregate.Entities;
using Oms.Domain.Shared.Enums;
using Oms.Domain.ChannelsAggregate.Repositories;
using Oms.SqlSugarCore.Repositories;
namespace Oms.SqlSugarCore.Channels;
public class ServiceChannelRepository : OmsSqlSugarRepository<ServiceChannel>, IServiceChannelRepository, IScopedDependency
{
public Task<ServiceChannel?> GetByChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default)
{
return FirstOrDefaultAsync(x => x.ChannelCode == channelCode, cancellationToken);
}
public async Task<ServiceChannel?> GetByChannelCodeIncludingDeletedAsync(
string channelCode,
CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await SoftDeleteQuery.FirstIncludingDeletedAsync<ServiceChannel>(
db,
x => x.ChannelCode == channelCode,
cancellationToken);
}
public Task<bool> HasChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default)
{
return AnyAsync(x => x.ChannelCode == channelCode, cancellationToken);
}
public async Task<List<ServiceChannelGroup>> GetGroupsAsync(CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelGroup>().ToListAsync(cancellationToken);
}
public async Task<List<ServiceChannelPrice>> GetPricesAsync(int serviceChannelId, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPrice>()
.Where(x => x.ServiceChannelId == serviceChannelId)
.OrderBy(x => x.SerialNumber)
.ToListAsync(cancellationToken);
}
public async Task<ServiceChannelPrice?> GetPriceByIdAsync(int id, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPrice>()
.FirstAsync(x => x.Id == id, cancellationToken);
}
public async Task<List<ServiceChannelPriceFactor>> GetPriceFactorsAsync(IEnumerable<int> priceIds, CancellationToken cancellationToken = default)
{
var ids = priceIds.Distinct().ToArray();
if (ids.Length == 0) return [];
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPriceFactor>()
.Where(x => ids.Contains(x.PriceId))
.OrderBy(x => x.SerialNumber)
.ToListAsync(cancellationToken);
}
public async Task<List<ServiceChannelPriceDetail>> GetPriceDetailsAsync(IEnumerable<int> priceIds, CancellationToken cancellationToken = default)
{
var ids = priceIds.Distinct().ToArray();
if (ids.Length == 0) return [];
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPriceDetail>()
.Where(x => ids.Contains(x.PriceId))
.ToListAsync(cancellationToken);
}
public async Task<ServiceChannelPrice> InsertPriceAsync(ServiceChannelPrice price, IEnumerable<ServiceChannelPriceFactor> factors, IEnumerable<ServiceChannelPriceDetail> details, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
price.Id = 0;
var savedPrice = await db.Insertable(price).ExecuteReturnEntityAsync();
await InsertPriceChildrenAsync(db, savedPrice.Id, factors, details, cancellationToken);
return savedPrice;
}
public async Task UpdatePriceAsync(ServiceChannelPrice price, IEnumerable<ServiceChannelPriceFactor> factors, IEnumerable<ServiceChannelPriceDetail> details, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
await db.Updateable(price).ExecuteCommandAsync(cancellationToken);
await db.Deleteable<ServiceChannelPriceFactor>()
.Where(x => x.PriceId == price.Id)
.ExecuteCommandAsync(cancellationToken);
await db.Deleteable<ServiceChannelPriceDetail>()
.Where(x => x.PriceId == price.Id)
.ExecuteCommandAsync(cancellationToken);
await InsertPriceChildrenAsync(db, price.Id, factors, details, cancellationToken);
}
public async Task DeletePriceAsync(int id, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
await db.Deleteable<ServiceChannelPrice>()
.Where(x => x.Id == id)
.ExecuteCommandAsync(cancellationToken);
await db.Deleteable<ServiceChannelPriceFactor>()
.Where(x => x.PriceId == id)
.ExecuteCommandAsync(cancellationToken);
await db.Deleteable<ServiceChannelPriceDetail>()
.Where(x => x.PriceId == id)
.ExecuteCommandAsync(cancellationToken);
}
public async Task UpdatePriceStatusAsync(int id, EnableStatus status, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
await db.Updateable<ServiceChannelPrice>()
.SetColumns(x => x.Status, status)
.Where(x => x.Id == id)
.ExecuteCommandAsync(cancellationToken);
}
public async Task ReplacePricesAsync(int serviceChannelId, IEnumerable<ServiceChannelPrice> prices, IEnumerable<ServiceChannelPriceFactor> factors, IEnumerable<ServiceChannelPriceDetail> details, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
var oldPrices = await db.Queryable<ServiceChannelPrice>()
.Where(x => x.ServiceChannelId == serviceChannelId)
.ToListAsync(cancellationToken);
var oldPriceIds = oldPrices.Select(x => x.Id).ToArray();
if (oldPriceIds.Length > 0)
{
// 批量保存时先整棵旧买价树软删,再写入新的快照数据。
await db.Deleteable<ServiceChannelPrice>().Where(x => oldPriceIds.Contains(x.Id)).ExecuteCommandAsync(cancellationToken);
await db.Deleteable<ServiceChannelPriceFactor>().Where(x => oldPriceIds.Contains(x.PriceId)).ExecuteCommandAsync(cancellationToken);
await db.Deleteable<ServiceChannelPriceDetail>().Where(x => oldPriceIds.Contains(x.PriceId)).ExecuteCommandAsync(cancellationToken);
}
var priceList = prices.Select(x => new
{
TempId = x.Id,
Entity = x
}).ToList();
if (priceList.Count == 0)
{
return;
}
var factorList = factors.ToList();
var detailList = details.ToList();
foreach (var item in priceList)
{
item.Entity.Id = 0;
item.Entity.ServiceChannelId = serviceChannelId;
var savedPrice = await db.Insertable(item.Entity).ExecuteReturnEntityAsync();
// 通过临时 PriceId 将因子和明细绑定回真实买价项主键。
await InsertPriceChildrenAsync(
db,
savedPrice.Id,
factorList.Where(x => x.PriceId == item.TempId),
detailList.Where(x => x.PriceId == item.TempId),
cancellationToken);
}
}
public async Task<List<ServiceChannelPublishRecord>> GetPublishRecordsAsync(int serviceChannelId, string operatorType, int pageIndex, int pageSize, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPublishRecord>()
.Where(x => x.ServiceChannelId == serviceChannelId && x.OperatorType == operatorType)
.OrderBy(x => x.PublishTime, SqlSugar.OrderByType.Desc)
.ToPageListAsync(pageIndex, pageSize, cancellationToken);
}
public async Task<int> CountPublishRecordsAsync(int serviceChannelId, string operatorType, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPublishRecord>()
.Where(x => x.ServiceChannelId == serviceChannelId && x.OperatorType == operatorType)
.CountAsync(cancellationToken);
}
public async Task<ServiceChannelPublishRecord> InsertPublishRecordAsync(ServiceChannelPublishRecord record, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Insertable(record).ExecuteReturnEntityAsync();
}
public async Task<ServiceChannelPublishRecord?> GetPublishRecordByIdAsync(int id, CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
return await db.Queryable<ServiceChannelPublishRecord>().FirstAsync(x => x.Id == id, cancellationToken);
}
public async Task<ServiceChannelPublishRecord?> GetEffectivePublishRecordAsync(
int serviceChannelId,
string operatorType,
DateTime bindTime,
CancellationToken cancellationToken = default)
{
var db = await GetDbContextAsync(cancellationToken);
var records = await db.Queryable<ServiceChannelPublishRecord>()
.Where(x => x.ServiceChannelId == serviceChannelId
&& x.OperatorType == operatorType
&& x.Status == EsSnapshotStatus.Active
&& x.PublishTime <= bindTime)
.OrderBy(x => x.PublishTime, SqlSugar.OrderByType.Desc)
.Take(1)
.ToListAsync(cancellationToken);
return records.FirstOrDefault();
}
private static async Task InsertPriceChildrenAsync(
SqlSugar.ISqlSugarClient db,
int priceId,
IEnumerable<ServiceChannelPriceFactor> factors,
IEnumerable<ServiceChannelPriceDetail> details,
CancellationToken cancellationToken)
{
// 子表在仓储层统一重写 PriceId,应用层只需要维护临时关联关系。
var factorArray = factors.Select(x =>
{
x.Id = 0;
x.PriceId = priceId;
return x;
}).ToArray();
if (factorArray.Length > 0)
{
await db.Insertable(factorArray).ExecuteCommandAsync(cancellationToken);
}
var detailArray = details.Select(x =>
{
x.Id = 0;
x.PriceId = priceId;
return x;
}).ToArray();
if (detailArray.Length > 0)
{
await db.Insertable(detailArray).ExecuteCommandAsync(cancellationToken);
}
}
}