33import org .springframework .stereotype .Service ;
44import org .springframework .transaction .annotation .Transactional ;
55import com .digitalsanctuary .spring .demo .event .Event ;
6+ import com .digitalsanctuary .spring .demo .event .EventRepository ;
67import com .digitalsanctuary .spring .user .persistence .model .User ;
78import com .digitalsanctuary .spring .user .persistence .repository .UserRepository ;
89import com .digitalsanctuary .spring .user .profile .UserProfileService ;
@@ -114,6 +115,7 @@ public class DemoUserProfileService implements UserProfileService<DemoUserProfil
114115
115116 private final DemoUserProfileRepository profileRepository ;
116117 private final UserRepository userRepository ;
118+ private final EventRepository eventRepository ;
117119
118120 /**
119121 * Retrieves an existing profile for the given user or creates a new one if none exists.
@@ -159,8 +161,44 @@ public DemoUserProfile updateProfile(DemoUserProfile profile) {
159161 return profileRepository .save (profile );
160162 }
161163
164+ /**
165+ * Registers a user profile for a specific event using IDs to ensure entities are managed.
166+ *
167+ * <p>
168+ * This method loads the profile and event as managed entities within the transaction,
169+ * avoiding issues with detached entities and cascade operations.
170+ *
171+ * @param profileId the ID of the profile to register for the event
172+ * @param eventId the ID of the event to register for
173+ * @return the updated profile with the event registration
174+ * @throws IllegalArgumentException if the profile or event is not found
175+ */
176+ @ Transactional
177+ public DemoUserProfile registerForEvent (Long profileId , Long eventId ) {
178+ // Load managed entities within the transaction
179+ DemoUserProfile profile = profileRepository .findById (profileId )
180+ .orElseThrow (() -> new IllegalArgumentException ("Profile not found with id: " + profileId ));
181+ Event event = eventRepository .findById (eventId )
182+ .orElseThrow (() -> new IllegalArgumentException ("Event not found with id: " + eventId ));
183+
184+ // Check if already registered
185+ if (profile .isRegisteredForEvent (event )) {
186+ log .info ("Profile {} is already registered for event {}" , profileId , eventId );
187+ return profile ;
188+ }
189+
190+ EventRegistration registration = new EventRegistration ();
191+ registration .setEvent (event );
192+ profile .addEventRegistration (registration );
193+
194+ // No explicit save needed - transaction will persist changes to managed entities
195+ return profile ;
196+ }
197+
162198 /**
163199 * Registers the given profile for a specific event.
200+ *
201+ * @deprecated Use {@link #registerForEvent(Long, Long)} instead to avoid issues with detached entities.
164202 *
165203 * <p>
166204 * This method demonstrates how to extend profile functionality with application-specific logic.
@@ -170,23 +208,47 @@ public DemoUserProfile updateProfile(DemoUserProfile profile) {
170208 * @return the updated profile with the event registration
171209 * @throws IllegalArgumentException if the profile or event is null
172210 */
173- @ Transactional // added to ensure the session remains active
211+ @ Deprecated
212+ @ Transactional
174213 public DemoUserProfile registerForEvent (DemoUserProfile profile , Event event ) {
175214 if (profile == null ) {
176215 throw new IllegalArgumentException ("Profile must not be null" );
177216 }
178217 if (event == null ) {
179218 throw new IllegalArgumentException ("Event must not be null" );
180219 }
220+
221+ // Delegate to the ID-based method to ensure we work with managed entities
222+ return registerForEvent (profile .getId (), event .getId ());
223+ }
181224
182- EventRegistration registration = new EventRegistration ();
183- registration .setEvent (event );
184- profile .addEventRegistration (registration );
185- return profileRepository .save (profile );
225+ /**
226+ * Unregisters a user profile from a specific event using IDs to ensure entities are managed.
227+ *
228+ * @param profileId the ID of the profile to unregister from the event
229+ * @param eventId the ID of the event to unregister from
230+ * @return the updated profile without the event registration
231+ * @throws IllegalArgumentException if the profile or event is not found
232+ */
233+ @ Transactional
234+ public DemoUserProfile unregisterFromEvent (Long profileId , Long eventId ) {
235+ // Load managed entities within the transaction
236+ DemoUserProfile profile = profileRepository .findById (profileId )
237+ .orElseThrow (() -> new IllegalArgumentException ("Profile not found with id: " + profileId ));
238+ Event event = eventRepository .findById (eventId )
239+ .orElseThrow (() -> new IllegalArgumentException ("Event not found with id: " + eventId ));
240+
241+ profile .removeEventRegistration (event );
242+ log .info ("Unregistered profile {} from event {}" , profileId , eventId );
243+
244+ // No explicit save needed - transaction will persist changes to managed entities
245+ return profile ;
186246 }
187247
188248 /**
189249 * Unregisters the given profile from a specific event.
250+ *
251+ * @deprecated Use {@link #unregisterFromEvent(Long, Long)} instead to avoid issues with detached entities.
190252 *
191253 * <p>
192254 * This method demonstrates how to extend profile functionality with application-specific logic.
@@ -196,15 +258,16 @@ public DemoUserProfile registerForEvent(DemoUserProfile profile, Event event) {
196258 * @return the updated profile without the event registration
197259 * @throws IllegalArgumentException if the profile or event is null
198260 */
261+ @ Deprecated
199262 public DemoUserProfile unregisterFromEvent (DemoUserProfile profile , Event event ) {
200263 if (profile == null ) {
201264 throw new IllegalArgumentException ("Profile must not be null" );
202265 }
203266 if (event == null ) {
204267 throw new IllegalArgumentException ("Event must not be null" );
205268 }
206- profile . removeEventRegistration ( event );
207- log . info ( "Unregistered profile {} from event {}" , profile . getId (), event . getId ());
208- return profileRepository . save (profile );
269+
270+ // Delegate to the ID-based method to ensure we work with managed entities
271+ return unregisterFromEvent (profile . getId (), event . getId () );
209272 }
210273}
0 commit comments