Объекты отношения один-к-одному такого же типа - PullRequest
0 голосов
/ 03 июля 2019

Я очень новичок в 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
    }

AvailableStudy:

   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.

Ответы [ 2 ]

1 голос
/ 03 июля 2019

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

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

0 голосов
/ 03 июля 2019

Я решил!

После синтаксического анализа файла JSON я вызывал следующие методы:

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

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

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

...