Преобразование отношения «многие ко многим» в отношение «родитель-потомок»

#c# #fluent-nhibernate

#c# #свободно-nhibernate

Вопрос:

У меня есть два класса User и Appointment, которые раньше были связаны отношением «многие ко многим». Но теперь я должен иметь возможность управлять состоянием этого отношения (мне нужно иметь возможность отслеживать, принял ли пользователь назначение, отклонил или еще не ответил).

Классы сопоставляются с соответствующими таблицами Users и Appointments. Обе таблицы связаны через таблицу назначений пользователей, которая имеет составной первичный ключ, состоящий из fk для пользователей и fk для таблицы назначений.

Текущая реализация выдает исключение с сообщением: «Недопустимый индекс 2 для этого SqlParameterCollection с Count=2″. когда я пытаюсь добавить НОВЫЙ объект назначения пользователя в коллекцию объекта назначения

Отображение пользователя

  public class UserMap : ClassMap<User>
    {
        public UserMap()
        {
            Id(d => d.Id);
            Map(d => d.FirstName).Column("FirstName");
            Map(d => d.LastName).Column("LastName");
            Map(d => d.Email).Column("Email");            
            HasMany(u => u.UserAppointments);  
            Table("Users");

        }
    }
  

Сопоставление назначений

 public class AppointmentMap : ClassMap<Appointment>
    {
        public AppointmentMap()
        {
            Id(c => c.Id);
            HasMany(a => a.AppointmentParticipants).Inverse().Cascade.All();
            References(a => a.Location).Column("FkAddressId");
            Map(a => a.DateAndTime).Column("AppointmentDate").CustomType<UtcDateTimeType>();
            Map(a => a.Description).Column("AppointmentDescription");
            Map(a => a.Status).Column("AppointmentStatus").CustomType<AppointmentStatus>();
            HasMany(a => a.AppointmentEstates).Inverse().Cascade.All();
            Table("Appointments");
        }
  

Сопоставление пользовательских назначений

 public class UserAppointmentsMap : ClassMap<UserAppointment>
    {
        public UserAppointmentsMap()
        {
            CompositeId()
                .KeyReference(a => a.Appointment, "FkAppointmentsId")
                .KeyReference(u => u.User, "FkUserId");
            References(a => a.User).Column("FkUserId");
            References(a => a.Appointment).Column("FkAppointmentsId");
            Table("UserAppointments");
        }
    }
  

Ожидаемый результат заключается в том, что когда я добавляю новое назначение пользователя в коллекцию существующего назначения, в таблице назначений пользователей создается новая запись, указывающая на соответствующий объект User и Appointment

Ответ №1:

Мне наконец удалось решить проблему…. На самом деле было несколько проблем с моим кодом:

  1. Проблема с «Недопустимым индексом 2 для этого SqlParameterCollection с Count = 2».было вызвано UserAppointmentsMap. После определения свойства как части составного ключа его не следует повторно отображать в качестве ссылки.

     public class UserAppointmentsMap : ClassMap<UserAppointment>
    {
        public UserAppointmentsMap()
        {
            CompositeId()
                .KeyReference(a => a.Appointment, "FkAppointmentsId")
                .KeyReference(u => u.User, "FkUserId");
            Table("UserAppointments");
        }
    }
      
  2. Составной идентификатор с внешним ключом должен выполняться с помощью KeyReference вместо KeyProperty

  3. У меня возникла проблема с неправильно сгенерированным запросом (внешний ключ был неправильным, т.Е. Вместо FkAppointmentsId он искал Appointments_Id), поэтому мне пришлось явно указать имя столбца

     public class AppointmentMap : ClassMap<Appointment>
    {
        public AppointmentMap()
        {
            Id(c => c.Id);
            HasMany(a => a.AppointmentParticipants).Inverse().KeyColumn("FkAppointmentsId").Cascade.All();
            References(a => a.Location).Column("FkAddressId");
            Map(a => a.DateAndTime).Column("AppointmentDate").CustomType<UtcDateTimeType>();
            Map(a => a.Description).Column("AppointmentDescription");
            Map(a => a.Status).Column("AppointmentStatus").CustomType<AppointmentStatus>();
            HasMany(a => a.AppointmentEstates).Inverse().KeyColumn("FkAppointmentsId").Cascade.All();
            Table("Appointments");
        }
    }