Язык программирования C#9 и платформа .NET5
// ApplicationDbContextprotected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Car>(entity =>{...<b> entity.Property(e => e.IsDrivable).HasDefaultValue(true);</b>});В случае если вы сохраните новую запись с
, то значениеIsDrivable = falseигнорируется (т.к. оно является стандартным значением для булевского типа) и будет применяться стандартное значение. Таким образом, значение дляfalseвсегда будет равноIsDrivable! Одно из решений предусматривает превращение вашего открытого свойства (и, следовательно, столбца) в допускающееtrue, но это может не соответствовать бизнес-потребностям.nullДругое решение предлагается инфраструктурой EF Core, в частности, ее работой с поддерживающими полями. Вспомните, что если поддерживающее поле существует (и идентифицируется как таковое для свойства через соглашение, аннотацию данных или Fluent API), тогда для действий по чтению и записи EF Core будет использовать поддерживающее поле, а не открытое свойство.
Если вы модифицируете
с целью применения поддерживающего поля, допускающегоIsDrivable(но оставите свойство не допускающимnull), то EF Core будет выполнять чтение и запись, используя поддерживающее поле, а не свойство. Стандартным значением для булевского типа, допускающегоnull, являетсяnull— неnull. Описанное изменение обеспечит ожидаемое поведение свойства:falsepublic class Car{...private bool? _isDrivable;public bool IsDrivable{get => _isDrivable ?? true;set => _isDrivable = value;}Для информирования EF Core о поддерживающем поле используется Fluent API:
modelBuilder.Entity<Car>(entity =>{entity.Property(p => p.IsDrivable)<b> .HasField("_isDrivable")</b>.HasDefaultValue(true);});На заметку! В приведенном примере вызов метода
не обязателен, потому что имя поддерживающего поля следует соглашениям об именовании. Он включен в целях демонстрации применения Fluent API для указания поддерживающего поля.HasField()Исполняющая среда EF Core транслирует поле в показанное ниже определение SQL:
CREATE TABLE [dbo].[Inventory](...<b> [IsDrivable] [BIT] NOT NULL,</b>...GO<b>ALTER TABLE [dbo].[Inventory] ADD DEFAULT (CONVERT([BIT],(1)))</b><b>FOR [IsDrivable]</b>GOВычисляемые столбцы
Столбцы также могут вычисляться на основе возможностей хранилища данных. Для SQL Server есть два варианта: вычислять значение, основываясь на других полях в той же самой записи, либо использовать скалярную функцию. Скажем, чтобы создать в таблице
вычисляемый столбец, который объединяет значенияInventoryиPetNameдля созданияColor, применяйте функциюDisplayName:HasComputedColumnSql()modelBuilder.Entity<Car>(entity =>{entity.Property(p => p.FullName)<b> .HasComputedColumnSql("[PetName] + ' (' + [Color] + ')'");</b>});В версии EF Core 5 появилась возможность сохранения вычисляемых значений, так что значение вычисляется только при создании или обновлении строки. Хотя в SQL Server упомянутая возможность поддерживается, она присутствует не во всех хранилищах данных, поэтому проверяйте документацию по своему поставщику баз данных:
modelBuilder.Entity<Car>(entity =>{entity.Property(p => p.FullName).HasComputedColumnSql("[PetName] + ' (' + [Color] + ')'", <b>stored:true</b>);});Отношения "один ко многим"
Чтобы определить отношение "один ко многим" с помощью Fluent API, выберите одну из сущностей, подлежащих обновлению. Обе стороны навигационной цепочки устанавливаются в одном блоке кода:
modelBuilder.Entity<Car>(entity =>{...entity.HasOne(d => d.MakeNavigation).WithMany(p => p.Cars).HasForeignKey(d => d.MakeId).OnDelete(DeleteBehavior.ClientSetNull).HasConstraintName("FK_Inventory_Makes_MakeId");});Если вы выберете в качестве основы для конфигурации навигационной сущности главную сущность, тогда код будет выглядеть примерно так:
modelBuilder.Entity<Make>(entity =>{