Browse Source

fix(EfCoreMessageRepository): 优化消息查询逻辑,解决在pgsql下报错的问题,合并用户消息和群组消息查询并简化代码结构。

pull/1048/head
feijie 1 year ago
parent
commit
89ac004859
  1. 329
      aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Chat/EfCoreMessageRepository.cs

329
aspnet-core/modules/realtime-message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Chat/EfCoreMessageRepository.cs

@ -1,4 +1,4 @@
using LINGYUN.Abp.IM.Messages; using LINGYUN.Abp.IM.Messages;
using LINGYUN.Abp.MessageService.EntityFrameworkCore; using LINGYUN.Abp.MessageService.EntityFrameworkCore;
using LINGYUN.Abp.MessageService.Groups; using LINGYUN.Abp.MessageService.Groups;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -170,274 +170,75 @@ public class EfCoreMessageRepository : EfCoreRepository<IMessageServiceDbContext
int maxResultCount = 10, int maxResultCount = 10,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
if (sorting.IsNullOrWhiteSpace()) // 参数验证和默认值设置
{ sorting = sorting.IsNullOrWhiteSpace() ? $"{nameof(LastChatMessage.SendTime)} DESC" : sorting;
sorting = $"{nameof(LastChatMessage.SendTime)} DESC";
}
var dbContext = await GetDbContextAsync(); var dbContext = await GetDbContextAsync();
var token = GetCancellationToken(cancellationToken);
#region SQL 原型
// 使用Union All合并用户消息和群组消息查询
//var sqlBuilder = new StringBuilder(1280); var lastMessages = await (
//sqlBuilder.AppendLine("SELECT"); // 用户消息查询
//sqlBuilder.AppendLine(" msg.* "); from um in dbContext.Set<UserMessage>()
//sqlBuilder.AppendLine("FROM"); join ucc in dbContext.Set<UserChatCard>()
//sqlBuilder.AppendLine(" ("); on um.CreatorId equals ucc.UserId
//sqlBuilder.AppendLine(" SELECT"); where um.ReceiveUserId == userId &&
//sqlBuilder.AppendLine(" um.Content,"); (state == null || um.State == state) &&
//sqlBuilder.AppendLine(" um.CreationTime,"); um.MessageId == (
//sqlBuilder.AppendLine(" um.CreatorId,"); from subUm in dbContext.Set<UserMessage>()
//sqlBuilder.AppendLine(" um.SendUserName,"); where subUm.ReceiveUserId == userId &&
//sqlBuilder.AppendLine(" ac.NickName AS Object,"); subUm.CreatorId == um.CreatorId
//sqlBuilder.AppendLine(" ac.AvatarUrl,"); select subUm.MessageId
//sqlBuilder.AppendLine(" um.Source,"); ).Max()
//sqlBuilder.AppendLine(" um.MessageId,"); select new LastChatMessage
//sqlBuilder.AppendLine(" um.Type,");
//sqlBuilder.AppendLine(" um.TenantId,");
//sqlBuilder.AppendLine(" um.ReceiveUserId,");
//sqlBuilder.AppendLine(" '' AS GroupId,");
//sqlBuilder.AppendLine(" um.ExtraProperties");
//sqlBuilder.AppendLine(" FROM");
//sqlBuilder.AppendLine(" (");
//sqlBuilder.AppendLine(" SELECT");
//sqlBuilder.AppendLine(" um.* ");
//sqlBuilder.AppendLine(" FROM");
//sqlBuilder.AppendLine(" appusermessages um");
//sqlBuilder.AppendLine(" INNER JOIN ( SELECT max( um.MessageId ) AS MessageId FROM appusermessages um");
//sqlBuilder.AppendLine(" WHERE");
//sqlBuilder.AppendLine(" um.ReceiveUserId = @ReceiveUserId");
//if (state.HasValue)
//{
// sqlBuilder.AppendLine(" AND um.State = @State");
//}
//if (CurrentTenant.IsAvailable)
//{
// sqlBuilder.AppendLine(" AND um.TenantId = @TenantId");
//}
//sqlBuilder.AppendLine(" GROUP BY um.ReceiveUserId ) gum ON um.MessageId = gum.MessageId");
//sqlBuilder.AppendLine(" ) um");
//sqlBuilder.AppendLine(" LEFT JOIN appuserchatcards ac ON ac.UserId = um.CreatorId ");
//sqlBuilder.AppendLine(" UNION ALL");
//sqlBuilder.AppendLine(" SELECT");
//sqlBuilder.AppendLine(" gm.Content,");
//sqlBuilder.AppendLine(" gm.CreationTime,");
//sqlBuilder.AppendLine(" gm.CreatorId,");
//sqlBuilder.AppendLine(" gm.SendUserName,");
//sqlBuilder.AppendLine(" ag.Name AS Object,");
//sqlBuilder.AppendLine(" ag.AvatarUrl,");
//sqlBuilder.AppendLine(" gm.Source,");
//sqlBuilder.AppendLine(" gm.MessageId,");
//sqlBuilder.AppendLine(" gm.Type,");
//sqlBuilder.AppendLine(" gm.TenantId,");
//sqlBuilder.AppendLine(" '' AS ReceiveUserId,");
//sqlBuilder.AppendLine(" gm.GroupId,");
//sqlBuilder.AppendLine(" gm.ExtraProperties");
//sqlBuilder.AppendLine(" FROM");
//sqlBuilder.AppendLine(" appgroupmessages gm");
//sqlBuilder.AppendLine(" INNER JOIN (");
//sqlBuilder.AppendLine(" SELECT");
//sqlBuilder.AppendLine(" max( gm.MessageId ) AS MessageId ");
//sqlBuilder.AppendLine(" FROM");
//sqlBuilder.AppendLine(" appuserchatcards ac");
//sqlBuilder.AppendLine(" LEFT JOIN appuserchatgroups acg ON acg.UserId = ac.UserId");
//sqlBuilder.AppendLine(" LEFT JOIN appgroupmessages gm ON gm.GroupId = acg.GroupId ");
//sqlBuilder.AppendLine(" WHERE");
//sqlBuilder.AppendLine(" ac.UserId = @ReceiveUserId ");
//if (state.HasValue)
//{
// sqlBuilder.AppendLine(" AND gm.State = @State");
//}
//if (CurrentTenant.IsAvailable)
//{
// sqlBuilder.AppendLine(" AND gm.TenantId = @TenantId");
//}
//sqlBuilder.AppendLine(" GROUP BY");
//sqlBuilder.AppendLine(" gm.GroupId");
//sqlBuilder.AppendLine(" ) ggm ON ggm.MessageId = gm.MessageId ");
//sqlBuilder.AppendLine(" INNER JOIN appchatgroups ag on ag.GroupId = gm.GroupId");
//sqlBuilder.AppendLine(" ) AS msg");
//sqlBuilder.AppendLine("ORDER BY ");
//sqlBuilder.AppendLine(" @Sorting");
//sqlBuilder.AppendLine(" LIMIT @MaxResultCount");
//using var dbContection = dbContext.Database.GetDbConnection();
//await dbContection.OpenAsync();
//using var command = dbContection.CreateCommand();
//command.Transaction = dbContext.Database.CurrentTransaction?.GetDbTransaction();
//command.CommandText = sqlBuilder.ToString();
//var receivedUser = command.CreateParameter();
//receivedUser.DbType = System.Data.DbType.Guid;
//receivedUser.ParameterName = "@ReceiveUserId";
//receivedUser.Value = userId;
//command.Parameters.Add(receivedUser);
//var sorttingParam = command.CreateParameter();
//sorttingParam.DbType = System.Data.DbType.String;
//sorttingParam.ParameterName = "@Sorting";
//sorttingParam.Value = sorting;
//command.Parameters.Add(sorttingParam);
//var limitParam = command.CreateParameter();
//limitParam.DbType = System.Data.DbType.Int32;
//limitParam.ParameterName = "@MaxResultCount";
//limitParam.Value = maxResultCount;
//command.Parameters.Add(limitParam);
//if (state.HasValue)
//{
// var stateParam = command.CreateParameter();
// stateParam.DbType = System.Data.DbType.Int32;
// stateParam.ParameterName = "@State";
// stateParam.Value = (int)state.Value;
// command.Parameters.Add(stateParam);
//}
//if (CurrentTenant.IsAvailable)
//{
// var tenantParam = command.CreateParameter();
// tenantParam.DbType = System.Data.DbType.Guid;
// tenantParam.ParameterName = "@TenantId";
// tenantParam.Value = CurrentTenant.Id.Value;
// command.Parameters.Add(tenantParam);
//}
//var messages = new List<LastChatMessage>();
//using var reader = await command.ExecuteReaderAsync();
//T GetValue<T>(DbDataReader reader, int index)
//{
// var value = reader.GetValue(index);
// if (value == null || value == DBNull.Value)
// {
// return default;
// }
// var valueType = typeof(T);
// var converter = TypeDescriptor.GetConverter(valueType);
// if (converter.CanConvertFrom(value.GetType()))
// {
// return (T)converter.ConvertFrom(value);
// }
// return (T)Convert.ChangeType(value, typeof(T));
//};
//ExtraPropertyDictionary GetExtraProperties(DbDataReader reader, int index)
//{
// var value = reader.GetValue(index);
// if (value == null || value == DBNull.Value)
// {
// return new ExtraPropertyDictionary();
// }
// var extraPropertiesAsJson = value.ToString();
// if (extraPropertiesAsJson.IsNullOrEmpty() || extraPropertiesAsJson == "{}")
// {
// return new ExtraPropertyDictionary();
// }
// var deserializeOptions = new JsonSerializerOptions();
// deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter());
// var dictionary = JsonSerializer.Deserialize<ExtraPropertyDictionary>(extraPropertiesAsJson, deserializeOptions) ??
// new ExtraPropertyDictionary();
// return dictionary;
//}
//while (reader.Read())
//{
// messages.Add(new LastChatMessage
// {
// Content = GetValue<string>(reader, 0),
// SendTime = GetValue<DateTime>(reader, 1),
// FormUserId = GetValue<Guid>(reader, 2),
// FormUserName = GetValue<string>(reader, 3),
// Object = GetValue<string>(reader, 4),
// AvatarUrl = GetValue<string>(reader, 5),
// Source = (MessageSourceType)GetValue<int>(reader, 6),
// MessageId = GetValue<string>(reader, 7),
// MessageType = (MessageType)GetValue<int>(reader, 8),
// TenantId = GetValue<Guid?>(reader, 9),
// ToUserId = GetValue<string>(reader, 10),
// GroupId = GetValue<string>(reader, 11),
// ExtraProperties = GetExtraProperties(reader, 12),
// });
//}
//return messages;
#endregion
#region 待 EF 团队解决此问题
//// 聚合用户消息
var aggreUserMsgIdQuery = dbContext.Set<UserMessage>()
.Where(msg => msg.ReceiveUserId == userId)
.WhereIf(state.HasValue, x => x.State == state)
.GroupBy(msg => msg.ReceiveUserId)
.Select(msg => new
{ {
MessageId = msg.Max(x => x.MessageId) Content = um.Content,
}); SendTime = um.CreationTime,
var joinUserMsg = from um in dbContext.Set<UserMessage>() FormUserId = um.CreatorId.Value,
join aum in aggreUserMsgIdQuery FormUserName = um.SendUserName,
on um.MessageId equals aum.MessageId Object = ucc.NickName,
join ucc in dbContext.Set<UserChatCard>() AvatarUrl = ucc.AvatarUrl,
on um.CreatorId equals ucc.UserId Source = um.Source,
select new LastChatMessage MessageId = um.MessageId.ToString(),
{ MessageType = um.Type,
Content = Convert.ToString(um.Content), TenantId = um.TenantId,
SendTime = um.CreationTime, ToUserId = um.ReceiveUserId.ToString(),
FormUserId = um.CreatorId.Value, GroupId = ""
FormUserName = Convert.ToString(um.SendUserName), })
Object = Convert.ToString(ucc.NickName), .Union(
AvatarUrl = Convert.ToString(ucc.AvatarUrl), // 群组消息查询
Source = um.Source, from gm in dbContext.Set<GroupMessage>()
MessageId = Convert.ToString(um.MessageId), join cg in dbContext.Set<ChatGroup>()
MessageType = um.Type, on gm.GroupId equals cg.GroupId
TenantId = um.TenantId, join ucg in dbContext.Set<UserChatGroup>()
ToUserId = Convert.ToString(um.ReceiveUserId), on new { GroupId = gm.GroupId, UserId = userId } equals new { ucg.GroupId, ucg.UserId }
GroupId = Convert.ToString(""), where (state == null || gm.State == state) &&
}; gm.MessageId == (
// 聚合群组消息 from subGm in dbContext.Set<GroupMessage>()
var aggreGroupMsgIdQuery = from ucc in dbContext.Set<UserChatCard>() where subGm.GroupId == gm.GroupId
join ucg in dbContext.Set<UserChatGroup>() select subGm.MessageId
on ucc.UserId equals ucg.UserId ).Max()
join gm in dbContext.Set<GroupMessage>() select new LastChatMessage
on ucg.GroupId equals gm.GroupId {
where ucc.UserId.Equals(userId) Content = gm.Content,
group gm by gm.GroupId into ggm SendTime = gm.CreationTime,
select new FormUserId = gm.CreatorId.Value,
{ FormUserName = gm.SendUserName,
MessageId = ggm.Max(gm => gm.MessageId), Object = cg.Name,
}; AvatarUrl = cg.AvatarUrl,
Source = gm.Source,
var joinGroupMsg = from gm in dbContext.Set<GroupMessage>() MessageId = gm.MessageId.ToString(),
join agm in aggreGroupMsgIdQuery MessageType = gm.Type,
on gm.MessageId equals agm.MessageId TenantId = gm.TenantId,
join cg in dbContext.Set<ChatGroup>() ToUserId = "",
on gm.GroupId equals cg.GroupId GroupId = gm.GroupId.ToString()
select new LastChatMessage }
{ )
Content = Convert.ToString(gm.Content), // 排序和分页
SendTime = gm.CreationTime,
FormUserId = gm.CreatorId.Value,
FormUserName = Convert.ToString(gm.SendUserName),
Object = Convert.ToString(cg.Name),
AvatarUrl = Convert.ToString(cg.AvatarUrl),
Source = gm.Source,
MessageId = Convert.ToString(gm.MessageId),
MessageType = gm.Type,
TenantId = gm.TenantId,
ToUserId = Convert.ToString(""),
GroupId = Convert.ToString(gm.GroupId)
};
return await joinUserMsg
.Concat(joinGroupMsg)
.OrderBy(sorting) .OrderBy(sorting)
.Take(maxResultCount) .Take(maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken)); .ToListAsync(token);
#endregion
return lastMessages;
} }
public async virtual Task<List<UserMessage>> GetUserMessagesAsync( public async virtual Task<List<UserMessage>> GetUserMessagesAsync(

Loading…
Cancel
Save