Один к одному объекту отношения одного типа

Я новичок в ASP.NetCore и EF Core.

Мне сложно понять, как справиться с этой ситуацией:

У меня есть список AvailableStudy, и в каждом исследовании есть список AvailableStage. Но также этап может зависеть от предыдущего этапа (но не является обязательным), и то же самое происходит с исследованиями, исследование может зависеть от предыдущего исследования. Вот классы моделей:

BusinessObject:

 public class BusinessObject : IBusinessObject
    {
        #region Constructors
        public BusinessObject()
        {
            Id = Guid.NewGuid().ToString();
        }

        public BusinessObject(string name) :  this()
        {
            Name = name;
        }
        #endregion

        #region IBusinessObject implementation
        public string Id { get; set; }
        public string Name { get; set; }

        #endregion
    }

Доступное исследование:

   public class AvailableStudy : BusinessObject
    {
        #region Constructors
        public AvailableStudy() : base()
        {
            Stages = new List<AvailableStage>();
        }

        public AvailableStudy(string name) : base(name)
        {
            Stages = new List<AvailableStage>();
        }
        #endregion


        [ForeignKey("DependsOn")]
        public string DependsOnId { get; set; }

        #region Lazy-Load Properties
        public virtual List<AvailableStage> Stages { get; set; }

        public virtual AvailableStudy DependsOn { get; set; }
        #endregion
    }

AvailableStage:

public class AvailableStage : BusinessObject
    {
        #region Constructors
        public AvailableStage() : base()
        {
        }

        public AvailableStage(string name) : base(name)
        {
        }

        public AvailableStage(string name, AvailableStudy study) : base(name)
        {
            Study = study;
        }
        #endregion


        #region Properties
        [Required]
        public string StudyId { get; set; }

        public double Percentage { get; set; }

        public int Duration { get; set; }

        [ForeignKey("DependsOn")]
        public string DependsOnId { get; set; }
        #endregion

        #region Lazy-Load Properties
        public virtual AvailableStage DependsOn { get; set; }

        [ForeignKey("StudyId")]
        public virtual AvailableStudy Study { get; set; }
        #endregion        
    }

И, наконец, OnModelCreating моего класса контекста:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<AvailableStudy>().ToTable("AvailableStudies");
            modelBuilder.Entity<AvailableStudy>().HasMany(i => i.Stages).WithOne(c => c.Study);
           modelBuilder.Entity<AvailableStudy>().HasOne(i => i.DependsOn);

            modelBuilder.Entity<AvailableStage>().ToTable("AvailableStages");
            modelBuilder.Entity<AvailableStage>().HasOne(i => i.Study).WithMany(u => u.Stages);
            modelBuilder.Entity<AvailableStage>().HasOne(i => i.DependsOn);         
        }

Я разбираю файл JSON, чтобы создать список исследований с их этапами и зависимостями.

Фрагмент файла JSON

{
  "Studies": [
    {
      "Name": "Concentrated",
      "DependsOn": "",
      "Stages": [
        {
          "Name": "IsConcentratedDone",
          "Percentage": 25,
          "Duration": 1
        },
        {
          "Name": "WasDescribed",
          "Percentage": 25,
          "Duration": 1
        },
        {
          "Name": "HasPhotos",
          "Percentage": 25,
          "Duration": 1
        },
        {
          "Name": "ReportFinished",
          "Percentage": 25,
          "Duration": 1
        }
      ]
    },
    {
      "Name": "AFT",
      "DependsOn": "Concentrated",
      "Stages": [
        {
          "Name": "IsMountDone",
          "Percentage": 25,
          "Duration": 1
        },
        {
          "Name": "SendedToIrradiation",
          "Percentage": 25,
          "Duration": 1
        },
        {
          "Name": "WasRecepted",
          "Percentage": 25,
          "Duration": 1
        },
        {
          "Name": "WasMeasured",
          "Percentage": 25,
          "Duration": 1
        }
      ]
    }
  ]
}

Затем я добавляю эти исследования в соответствующий DBSet в классе DBContext, и когда я пытаюсь сохранить изменения, выдает исключение, в котором говорится:

SqlException: оператор INSERT конфликтует с ограничением FOREIGN KEY SAME TABLE «FK_AvailableStages_AvailableStages_DependsOnId». Конфликт произошел в базе данных «LateAndesSamples», таблица «dbo.AvailableStages», столбец «Id». Заявление было прекращено.

Я действительно не понимаю, что происходит.

Спасибо за вашу помощь!

Полный результат исключения:

Microsoft.EntityFrameworkCore.DbUpdateException
  HResult=0x80131500
  Message=An error occurred while updating the entries. See the inner exception for details.
  Source=Microsoft.EntityFrameworkCore.Relational
  StackTrace:
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IReadOnlyList`1 entries)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
   at LabManager.DataModel.Data.DbSeeder.CreateStudiesWithStages(ApplicationDbContext dbContext) in W:\LabManager\DataModel\src\Data\DbSeeder.cs:line 113
   at LabManager.DataModel.Data.DbSeeder.Seed(ApplicationDbContext dbContext, RoleManager`1 roleManager, UserManager`1 userManager, IHostingEnvironment env) in W:\LabManager\DataModel\src\Data\DbSeeder.cs:line 22
   at LabManagerWebPage.Extensions.ServiceExtensions.ConfigureDBContext(IApplicationBuilder app, IHostingEnvironment env) in W:\LabManager\LabManagerWebPage\Extensions\ServiceExtensions.cs:line 156
   at LabManagerWebPage.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env) in W:\LabManager\LabManagerWebPage\Startup.cs:line 107

Inner Exception 1:
SqlException: The INSERT statement conflicted with the FOREIGN KEY SAME TABLE constraint "FK_AvailableStages_AvailableStages_DependsOnId". The conflict occurred in database "LateAndesSamples", table "dbo.AvailableStages", column 'Id'.
The statement has been terminated.

person joaco    schedule 03.07.2019    source источник


Ответы (2)


Ваша проблема в базовом классе. Это должно быть абстрактно. В противном случае он создаст реляционное наследование, и единственная стратегия, поддерживаемая EF Core, - это иерархия таблицы на иерархию, также известная как однотабличное наследование. Это означает, что для кажущегося глобальным базовым классом, такого как BusinessObject, вы получите одну огромную таблицу, в которую будут помещены все ваши другие типы. Другими словами, бардак.

Сделав его абстрактным, производные типы унаследуют поведение, но каждый из них по-прежнему получит свои собственные таблицы.

person Chris Pratt    schedule 03.07.2019
comment
Спасибо за ответ! Извините за вопрос новичка, но это не решается с помощью метода OnModelCreating, когда вызывается modelBuilder.Entity ‹AvailableStudy› () .ToTable (AvailableStudies); ... и т. Д.? - person joaco; 03.07.2019
comment
Во всяком случае, я последовал твоему совету, Чирс. Еще раз спасибо! - person joaco; 03.07.2019

Я решил!

После разбора файла JSON я вызывал следующие методы:

//availables is a list of availiables studies generated after parsing json file

dbContext.AvailableStudies.AddRange(availables);
dbContext.SaveChanges();

Но когда я посмотрел подробно, этапы без зависимостей содержат пустую строку в свойстве DependsOnId вместо null. После замены пустых строк на null все работает нормально!

person joaco    schedule 03.07.2019