its not there anymore (commented out)
with that: " public async Task<MeetingDto> UpdateAsync(Guid meetingId, Guid userId, MeetingDto input, UserModeDto userMode) { #region Allgemein: Validierung // Lade das Meeting mit zugehörigen Details (Participants) aus dem Repository var queryableMeeting = await _meetingRepository.WithDetailsAsync(m => m.Participants); var meetingQuery = queryableMeeting.Where(x => x.Id == meetingId); var meeting = await AsyncExecuter.FirstOrDefaultAsync(meetingQuery);
// Überprüfe, ob das Meeting existiert
if (meeting == null)
{
throw new BusinessException($"Meeting mit Id {meetingId} nicht gefunden.");
}
// Prüfe, ob der anfragende Benutzer Teilnehmer des Meetings ist
var participant = meeting.Participants.FirstOrDefault(p => p.UserId == userId);
if (participant == null)
{
throw new BusinessException("Sie haben keinen Zugriff auf dieses Meeting.");
}
#endregion
// Optimistic Concurrency: Setze den ConcurrencyStamp des geladenen Meeting-Entities
// auf den vom Frontend gelieferten Wert. So erkennt das EF/ABP-Framework,
// falls das Meeting zwischenzeitlich von jemand anderem geändert wurde.
//meeting.ConcurrencyStamp = input.ConcurrencyStamp;
// Alle folgenden DB-Änderungen laufen in einer Transaktion (ABP UnitOfWork),
// um Konsistenz sicherzustellen – entweder werden alle Änderungen gespeichert oder keine.
try
{
#region Globale Überschreibung der AllMoodTypes (nur Admin)
if (userMode == UserModeDto.Admin)
{
// 1. Lösche alle MoodTypes, die vom Administrator zum Entfernen markiert wurden
foreach (var moodTypeDto in input.AllMoodTypes.Where(m => m.Delete))
{
// Löschen des MoodType (falls bereits von anderem Admin gelöscht, wirft dies eine Exception)
await _moodTypeRepository.DeleteAsync(moodTypeDto.Id);
}
// 2. Lade die verbleibenden existierenden MoodTypes aus der DB (nach evtl. Löschungen)
var existingMoodTypes = await _moodTypeRepository.GetListAsync();
// 3. Füge neue MoodTypes hinzu oder aktualisiere bestehende anhand der Admin-Eingaben
foreach (var moodTypeDto in input.AllMoodTypes)
{
if (moodTypeDto.Delete)
{
// Überspringe MoodTypes, die bereits gelöscht wurden
continue;
}
var moodTypeEntity = existingMoodTypes.FirstOrDefault(mt => mt.Id == moodTypeDto.Id);
if (moodTypeEntity == null)
{
// MoodType existiert noch nicht -> neu anlegen
var newMoodType = new MoodType
{
Name = moodTypeDto.Name,
Description = moodTypeDto.Description,
Color = moodTypeDto.Color,
CreatedAt = DateTime.UtcNow
// Id (Key) wird bei Bedarf vom ORM/DB vergeben (z.B. Identity oder Guid über GuidGenerator)
};
await _moodTypeRepository.InsertAsync(newMoodType);
}
else
{
// MoodType existiert bereits -> aktualisieren
// Setze auch hier den ConcurrencyStamp, um parallele Änderungen an MoodTypes zu erkennen
//moodTypeEntity.ConcurrencyStamp = moodTypeDto.ConcurrencyStamp;
moodTypeEntity.Name = moodTypeDto.Name;
moodTypeEntity.Description = moodTypeDto.Description;
moodTypeEntity.Color = moodTypeDto.Color;
moodTypeEntity.UpdatedAt = DateTime.UtcNow;
await _moodTypeRepository.UpdateAsync(moodTypeEntity);
}
}
}
#endregion
#region Vorhandene Moods überschreiben bzw. hinzufügen (MoodVotes)
if (input.AllMoodTypes != null && input.AllMoodTypes.Count > 0)
{
// Entferne alle bisherigen MoodVotes des Teilnehmers, um sie durch die neuen zu ersetzen
await _moodVoteRepository.DeleteAsync(mv => mv.ParticipantId == participant.Id);
// Lege für jeden im Frontend ausgewählten MoodType einen neuen MoodVote an
foreach (var moodTypeDto in input.AllMoodTypes)
{
if (moodTypeDto.Selected)
{
var newMoodVote = new MoodVote
{
ParticipantId = participant.Id,
MoodTypeId = moodTypeDto.Id,
VoteTime = DateTime.UtcNow
};
await _moodVoteRepository.InsertAsync(newMoodVote);
}
}
}
#endregion
#region Hinzufügen neuer Nachrichten (UserMessages) für den Teilnehmer
// Speichere alle neuen Nachrichten, die vom Teilnehmer im Frontend hinzugefügt wurden
foreach (var messageDto in (input.UserMessages ?? new List<MessageDto>()))
{
var newMessage = new Message
{
ParticipantId = participant.Id,
CurrentMessage = messageDto.CurrentMessage,
CreatedAt = DateTime.UtcNow
};
await _messageRepository.InsertAsync(newMessage);
}
#endregion
#region Sonstige Eigenschaften aktualisieren
// Aktualisiere die Meeting-Eigenschaften
meeting.ScheduledTime = input.ScheduledTime;
meeting.UpdatedAt = DateTime.UtcNow;
#endregion
// Speichere die Änderungen am Meeting (ConcurrencyStamp wird vom Framework geprüft)
var updatedMeeting = await _meetingRepository.UpdateAsync(meeting);
#region DTO vorbereiten (Ergebnis für das Frontend)
// Mappe das aktualisierte Meeting-Entity zurück auf das MeetingDto
var meetingDto = ObjectMapper.Map<Meeting, MeetingDto>(updatedMeeting);
#region AllMoodTypes für das Ausgabe-DTO
// Hole die aktuelle Liste aller MoodTypes aus der Datenbank
var moodTypes = await _moodTypeRepository.GetListAsync();
// Markiere im MoodType-Listening diejenigen als 'Selected', die der Teilnehmer jetzt ausgewählt hat
if (participant.MoodVotes != null && participant.MoodVotes.Any())
{
// Falls die MoodVotes des Teilnehmers bereits im Kontext verfügbar sind, nutze sie
foreach (var vote in participant.MoodVotes)
{
var moodType = moodTypes.FirstOrDefault(m => m.Id == vote.MoodTypeId);
if (moodType != null)
{
moodType.Selected = true;
}
}
}
else
{
// Falls die MoodVotes nicht im Kontext geladen sind, verwende die aktuelle Auswahl aus dem Input
foreach (var moodTypeDto in input.AllMoodTypes)
{
var moodType = moodTypes.FirstOrDefault(m => m.Id == moodTypeDto.Id);
if (moodType != null)
{
moodType.Selected = moodTypeDto.Selected;
}
}
}
// Wandle die MoodType-Entitäten in DTOs um (immer eine Liste bereitstellen, auch wenn leer)
meetingDto.AllMoodTypes = moodTypes.Any()
? ObjectMapper.Map<List<MoodType>, List<MoodTypeDto>>(moodTypes)
: new List<MoodTypeDto>();
#endregion
#region UserMessages für das Ausgabe-DTO
// Hole alle Nachrichten für den Teilnehmer und mappe sie auf DTOs
var messages = await _messageRepository.GetListAsync(m => m.ParticipantId == participant.Id);
meetingDto.UserMessages = messages.Any()
? ObjectMapper.Map<List<Message>, List<MessageDto>>(messages)
: new List<MessageDto>();
#endregion
#endregion
// Gebe das aktualisierte Meeting als DTO zurück
return meetingDto;
}
catch (AbpDbConcurrencyException)
{
// Falls zwischen Laden und Speichern eine parallele Änderung entdeckt wurde (optimistische Sperre),
// wird eine verständliche Ausnahme geworfen, die z.B. im Frontend angezeigt werden kann.
throw new BusinessException("Das Meeting wurde in der Zwischenzeit von einem anderen Benutzer geändert. Bitte laden Sie die Seite neu und versuchen Sie es erneut.");
}
}"
Is there a pssebility to deactivate the Concurrency Check entirely?:
That I dont get: "The data you have submitted has already been changed by another user. Discard your changes and try again."
I chagned the classes, but I still get it (after time): " [Serializable] public class MeetingDto : EntityDto<Guid>//, IHasConcurrencyStamp { public string Title { get; set; } public DateTime UpdatedAt { get; set; }
public DateTime ScheduledTime { get; set; }
public List<ParticipantDto> Participants { get; set; }
public List<MoodTypeDto> AllMoodTypes { get; set; }
//public List<MoodVoteDto> UserMoodVotes { get; set; }
public List<MessageDto> UserMessages { get; set; }
//public string ConcurrencyStamp { get; set; } // muss vom Client mitgesendet werden
}
[Serializable] public class ParticipantDto : EntityDto<Guid> { public Guid UserId { get; set; } public Guid MeetingId { get; set; }
public UserModeDto eUserMode { get; set; }
public List<MoodVoteDto> MoodVotes { get; set; }
public List<MessageDto> Messages { get; set; }
public DateTime LastHeartbeat { get; set; }
public string UserAgent { get; set; }
public bool IsInactive { get; set; }
}
[Serializable] public class MessageDto : CreationAuditedEntityDto<Guid> { public Guid ParticipantId { get; set; } public string CurrentMessage { get; set; } public DateTime CreatedAt { get; set; } }
[Serializable] public class MoodVoteDto : EntityDto<Guid> { public bool Selected { get; set; } // Wird im FrontEnd gebraucht public Guid ParticipantId { get; set; }
public Guid MoodTypeId { get; set; }
public DateTime VoteTime { get; set; }
}
[Serializable]
public class MoodTypeDto : EntityDto<Guid>
{
public bool Selected { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Color { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public bool Delete { get; set; } = false;
}
[Serializable] public class MeetingStatusDto : EntityDto<Guid> { public Guid MeetingId { get; set; } public int TotalParticipants { get; set; } public List<MoodSummaryDto> MoodSummary { get; set; } public List<MessageDto> Messages { get; set; } }
[Serializable] public class MoodSummaryDto : EntityDto<Guid> { public Guid MoodTypeId { get; set; } public int VoteCount { get; set; } }
[Serializable] public class UserAccessDto : EntityDto<Guid> { public Guid ParticipantId { get; set; } public string UserAgent { get; set; } public UserModeDto eUserMode { get; set; } public string LastSeen { get; set; } public string IsActive { get; set; }
}" and " public class Meeting :BasicAggregateRoot<Guid>//, IHasConcurrencyStamp { //public override string ConcurrencyStamp { get; set; } = null; public string Title { get; set; } public DateTime ScheduledTime { get; set; } public DateTime UpdatedAt { get; set; }
public List<Participant> Participants { get; set; }
public Meeting(Guid id, string title, DateTime scheduledTime)
: base(id)
{
Title = title;
ScheduledTime = scheduledTime;
Participants = new List<Participant>();
}
}
public class Participant : Entity<Guid> { public Guid UserId { get; set; } public Guid MeetingId { get; set; } public UserMode eUserMode { get; set; } public Meeting Meeting { get; set; } public List<MoodVote> MoodVotes { get; set; } public List<Message> Messages { get; set; } public DateTime LastHeartbeat { get; set; } public string UserAgent { get; set; } public bool IsInactive { get; set; } }
public class Message : Entity<Guid> {
public Guid ParticipantId { get; set; }
public Participant Participant { get; set; }
public string CurrentMessage { get; set; }
public DateTime CreatedAt { get; set; }
}
public class MoodVote : Entity<Guid> { public Guid ParticipantId { get; set; } public Participant Participant { get; set; } public Guid MoodTypeId { get; set; } public MoodType MoodType { get; set; } public DateTime VoteTime { get; set; } }
public class MoodType : Entity<Guid> { [NotMapped] public bool Selected { get; set; } // Wird im FrontEnd gebraucht
public string Name { get; set; }
public string Description { get; set; }
public string Color { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public enum UserMode { User = 0, Admin = 1, Verwalter = 2 }"
Alright, but simply posting a link doesn’t really justify deducting a credit from my ticket budget—especially since we ended up finding a different solution.
SQL Server Version 11.00.6567 Windows Server 2019 abp package version: 9.x
Okay, we look forward to getting this issue resolved.
https://easyupload.io/08fu7n
https://easyupload.io/hout42
"For, ɵtriggerResourceLoading, ɵtruncateMiddle, ɵunregisterLocaleData, ɵunwrapSafeValue, ɵunwrapWritableSignal, ɵwhenStable, ɵwithDomHydration, ɵwithEventReplay, ɵwithI18nSupport, ɵɵCopyDefinitionFeature, ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcomponentInstance, ɵɵconditional, ɵɵcontentQuery, ɵɵcontentQuerySignal, ɵɵdeclareLet, ɵɵdefer, ɵɵdeferEnableTimerScheduling, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareClassMetadataAsync, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryAdvance, ɵɵqueryRefresh, ɵɵreadContextLet, ɵɵreference, ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstoreLet, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵtwoWayBindingSet, ɵɵtwoWayListener, ɵɵtwoWayProperty, ɵɵvalidateIframeAttribute, ɵɵviewQuery, ɵɵviewQuerySignal)
@volo/abp.commercial.ng.ui/config:285:35-56 - Error: export 'provideAppInitializer' (imported as 'provideAppInitializer') was not found in '@angular/core' (possible exports: ANIMATION_MODULE_TYPE, A... "
plus a lot of more ... upload does not work here