Не удается вставить значение NULL в столбец, таблицу; столбец не допускает нулей. ОШИБКА вставки

#c# #sql #nhibernate #fluent-nhibernate

#c# #sql #nhibernate #fluent-nhibernate

Вопрос:

Я нашел много похожих вопросов по SO, я пробовал указанные решения, но ни одно из них не сработало для меня, кто-нибудь может сказать мне, что было не так в следующем коде, какие исправления необходимо внести, чтобы сделать его работоспособным:

Модели:

 public class ParentDataClassData
    {
        public ParentDataClassData()
        {
            TitleSetTitles = new List<ChildDataClass1>();
            TitlesSetEvents = new List<ChildDataClass2>();
        }

        public virtual int TitleSetID { get; set; }
        public virtual string Name { get; set; }
        public virtual IList<ChildDataClass1> TitleSetTitles { get; set; }

        public virtual IEnumerable<ChildDataClass2> TitlesSetEvents { get; set; }

        public virtual object IdentityField
        {
            get { return TitleSetID; }
        }
    }


public class ChildDataClass1
    {
        public ChildDataClass1()
        {
            TitleSet = new ParentDataClassData();
            TitleSetTitleEventMedias = new List<TitleSetTitleEventMediaData>();
        }

        public virtual int TitleSetID
        {
            get { return TitleSet.TitleSetID; }
        }

        public virtual ParentDataClassData TitleSet { get; set; }

        public virtual IList<TitleSetTitleEventMediaData> TitleSetTitleEventMedias { get; set; }

        public virtual object IdentityField
        {
            get { return TitleSetTitleID; }
        }

    }


 public class ChildDataClass2
    {
        public virtual ParentDataClassData TitleSet { get; set;  }

        public virtual int TitleSetEventID
        {
            get;
            set;
        }


        public virtual object IdentityField
        {
            get { return TitleSetEventID; }
        }
    }
  

Сопоставления:

 public class ParentDataClassMap : ClassMap<ParentDataEntity>
    {
        public ParentDataClassMap()
        {
            Table("TitleSet");

            LazyLoad();

            Id(x => x.TitleSetID)
                .Column("TitleSetID")
                .GeneratedBy.Native()
                .UnsavedValue(0);


            HasMany(x => x.TitleSetTitles)
            .LazyLoad()
            .Inverse()
            .Fetch.Subselect()
            .Cascade.SaveUpdate()
            .KeyColumn("TitleSetID");

            HasMany(x => x.TitlesSetEvents)
                .LazyLoad()
                .Inverse()
                .Cascade.SaveUpdate()
                .Fetch.Subselect()
                .KeyColumn("TitleSetID");
        }
    }


 public class ChildDataClass1Map : ClassMap<ChildDataClass1>
    {
        public ChildDataClass1Map()
        {
            Table("TitleSetTitle");

            Id(x => x.TitleSetTitleID)
                .Column("TitleSetTitleID")
                .GeneratedBy.Native()
                .UnsavedValue(0);

            References(x => x.TitleSet)
                .Fetch.Join()
                .Not.Nullable()
                .Column("TitleSetID")
                .Cascade.None();


            HasMany(x => x.TitleSetTitleEventMedias)
                .LazyLoad()
                .Inverse()
                .Cascade.AllDeleteOrphan()
                .Fetch.Subselect()
                .KeyColumn("TitleSetTitleID");
        }
}


 public class ChildDataClass2Map : ClassMap<ChildDataClass2>
    {
        public ChildDataClass2Map()
        {
            Table("TitleSetEvent");

            Id(x => x.TitleSetEventID)
                .Column("TitleSetEventID")
                .GeneratedBy.Native()
                .UnsavedValue(0);


            References(x => x.TitleSet)
                .Column("TitleSetID")
                .Not.Update()
                .Not.Insert()
                .Cascade.None();

            Map(x => x.LengthSec).Not.Nullable();
            Map(x => x.EventID).Not.Nullable();

            HasMany(x => x.TitleSetDefaultEventMedia)
                .LazyLoad()
                .Inverse()
                .Cascade.None()
                .Fetch.Join()
                .KeyColumn("TitleSetEventID");

            HasMany(x => x.TitleSetTitleEventMedias)
                .LazyLoad()
                .Inverse()
                .Cascade.None()
                .Fetch.Join()
                .KeyColumn("TitleSetEventID");
        }
    }
  

Тест:

 [Test]
        public void CanAddNewTitleSet()
        {
            var titleSet = new TitleSetDataEntity
                {
                    Name = "Somename",
                    ProgramServiceID = 1,
                    CreatedBy = "someuser",
                    CreatedDate = DateTime.Now,
                    ModifiedBy = "someuser",
                    ModifiedDate = DateTime.Now,
                    TitleSetTitles = new List<TitleSetTitleData>
                    {
                        new TitleSetTitleData
                        {
                            IsIncluded = true,
                            IsPremiere = true,
                            TitleTypeCode = "somecode",
                        }
                    },
                    TitlesSetEvents = new List<TitleSetEventData>()
                };


                Session.SaveOrUpdate(titleSet);

            }
  

и получение исключения:

NHibernate .AdoNet.AbstractBatcher: ОШИБКА NHibernate .AdoNet.AbstractBatcher [(null)] — не удалось выполнить запрос: ВСТАВИТЬ В TitleSetTitle ([titleID], …, TitleSetID) ЗНАЧЕНИЯ (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8); выберите SCOPE_IDENTITY() System.Data.SqlClient.SQLException (0x80131904): не удается вставить значение NULL в столбец ‘TitleSetID’, таблицу ‘TitleSetTitle’; столбец не допускает нулей. ОШИБКА вставки. Оператор был завершен.

PS

  1. Я использовал обратное из двунаправленных отображений
  2. Во всяком случае, inverse не подчиняется вещам, насколько я понимаю, сначала он должен сохраняться ParantClassData , чтобы убедиться Child , что классы получают правильные идентификаторы.
  3. Не уверен, что я пропустил

Любая помощь по вышеуказанной проблеме будет горячо оценена!

Обновление Добавлено больше информации для объяснения проблемы, вместо длинного кода, мне просто интересно, есть ли TitleSetID проблема, связанная со свойством, доступным только для чтения.

Комментарии:

1. Прекратить попытки вставить значение null в TitleSetID ?

2. Сократите код до наименьшего примера, который отображает ошибку. Вы пытаетесь вставить NULL в TitleSetID или вы не включены TitleSetID в список вставки.

3. Я не предоставляю никакого нулевого значения TitleSetID , см. Мой тест, просто пытаюсь вставить новую коллекцию.

4. См. Ответ от @DanielKelley . Основная проблема заключается в его описании, а не в его названии

Ответ №1:

Проблема на самом деле скрыта в этом сопоставлении:

 HasMany(x => x.TitleSetTitles)
    ...
    .Inverse();
  

Это сопоставление инструктирует NHibernate:

Chlild позаботится об этом отношении.

Но это означает, что дочерний элемент должен знать о своем родителе. что неверно в этом коде:

 var titleSet = new TitleSetDataEntity
{
    Name = "Somename",
    ...
    TitleSetTitles = new List<TitleSetTitleData>
    {
        new TitleSetTitleData...
    },
};
session.Save(titleSet);
  

В этом коде в дочернем экземпляре, созданном с помощью new TitleSetTitleData , отсутствует родительская ссылка! И в этом проблема

ПРИМЕЧАНИЕ — я предполагаю, что свойство TitleSetTitles имеет тип IList<ChildDataClass1> TitleSetTitles , но в коде, который мы используем new List<TitleSetTitleData> … Я думаю, это опечатка

Правильный синтаксис будет:

 var titleSet = new TitleSetDataEntity
{
    Name = "Somename",
    ...
    TitleSetTitles = new List<TitleSetTitleData>();
};
var child = new TitleSetTitleData
{
    ...
    ParentDataClassData = titleSet,
};
titleSet.TitleSetTitles.Add(child);
session.Save(titleSet);
  

И теперь у NHibernate будет достаточно информации. Parent Child добавлен в список, Child знает о Parent .Inverse() том, что сопоставление и будет работать, потому что идентификатор родительского элемента больше не будет нулевым

Комментарии:

1. это модель: поле идентификатора объекта. Я не могу изменить схему таблицы, поскольку это устаревшее приложение. Кроме того, я проверил этот столбец, если столбец идентификатора в Table TitleSet .

2. Я обновил свой ответ, он должен четко показать вам, что нам нужно установить обе стороны отношения родитель-потомок. Если это значение будет установлено, все инструкции SQL будут обработаны правильно…

3. Спасибо за вашу помощь, я пытался, но все та же ошибка, я также ссылался this:nanovazquez.com/2013/07/04 / … но ничего не стоит, во всяком случае, каждый TitleSetID раз имеет значение null, и это происходит только тогда, когда я пытаюсь сохранить TitleSet с его дочерними элементами, например TitleSetTitles , если нет дочерних коллекций, тогда все работает нормально, это происходит только тогда, когда я попытался сохранить егокак с родительским, так и с дочерним.

4. Теперь мои тесты пройдены. Я изучаю свои реальные вещи, надеюсь, все будет хорошо, я отметил 1 ваш ответ, поскольку ваш ответ действительно полезен, я оценил ваше время, потраченное на этот разговор. Что касается отрицательного ответа на мой вопрос, я не уверен, почему ребята не смотрят на реальную проблему, я считаю, что они просто прочитали вопрос, а не описание, надеюсь, я мог бы задать это модератору SO, в любом случае, вы мне очень помогли.

5. ОТЛИЧНАЯ работа, сэр! Пожалуйста, не сдавайтесь из-за нескольких сомнительных голосов «против»… Наслаждайтесь NHibernate … блестящий инструмент 😉

Ответ №2:

Подобные ошибки обычно возникают всякий раз, когда вы пытаетесь вставить значение NULL в столбец, или вы забываете включить столбец в инструкцию insert, поскольку для некоторых настроек столбца требуются данные, и их нельзя оставлять пустыми. Убедитесь TitleSetID , что вы включаете в инструкцию insert и вводите в нее ненулевое значение.

Комментарии:

1. Я просто пытаюсь вставить коллекцию, см. Мой тест TitleSetID должен быть автоматически заполнен ключом родительского элемента, пока мы сохраняем дочернюю коллекцию