不幸的是,目前(从 EF Core 2.0.1 开始)这种行为是不可控的。我想它应该是对 EF6 的改进,因为它允许您执行身份插入。
幸运的是,EF Core 构建在基于服务的架构上,它允许您((虽然不是那么容易)替换几乎所有方面。在这种情况下,负责的服务称为 IValueGenerationManager 并由 ValueGenerationManager 类实现。提供上述行为的行是
private static IEnumerable<IProperty> FindPropagatingProperties(InternalEntityEntry entry)
=> entry.EntityType.GetProperties().Where(
property => property.IsForeignKey()
&& property.ClrType.IsDefaultValue(entry[property]));
private static IEnumerable<IProperty> FindGeneratingProperties(InternalEntityEntry entry)
=> entry.EntityType.GetProperties().Where(
property => property.RequiresValueGenerator()
&& property.ClrType.IsDefaultValue(entry[property]));
特别是&& property.ClrType.IsDefaultValue(entry[property]) 条件。
如果这些方法是 virtual 会很好,但它们不是,所以为了删除该检查,您基本上需要复制几乎所有代码。
将以下代码添加到项目中的新代码文件中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.ValueGeneration;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace Microsoft.EntityFrameworkCore
{
public static class Extensions
{
public static DbContextOptionsBuilder UseEF6CompatibleValueGeneration(this DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<IValueGenerationManager, EF6CompatibleValueGeneratorManager>();
return optionsBuilder;
}
}
}
namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal
{
public class EF6CompatibleValueGeneratorManager : ValueGenerationManager
{
private readonly IValueGeneratorSelector valueGeneratorSelector;
private readonly IKeyPropagator keyPropagator;
public EF6CompatibleValueGeneratorManager(IValueGeneratorSelector valueGeneratorSelector, IKeyPropagator keyPropagator)
: base(valueGeneratorSelector, keyPropagator)
{
this.valueGeneratorSelector = valueGeneratorSelector;
this.keyPropagator = keyPropagator;
}
public override InternalEntityEntry Propagate(InternalEntityEntry entry)
{
InternalEntityEntry chosenPrincipal = null;
foreach (var property in FindPropagatingProperties(entry))
{
var principalEntry = keyPropagator.PropagateValue(entry, property);
if (chosenPrincipal == null)
chosenPrincipal = principalEntry;
}
return chosenPrincipal;
}
public override void Generate(InternalEntityEntry entry)
{
var entityEntry = new EntityEntry(entry);
foreach (var property in FindGeneratingProperties(entry))
{
var valueGenerator = GetValueGenerator(entry, property);
SetGeneratedValue(entry, property, valueGenerator.Next(entityEntry), valueGenerator.GeneratesTemporaryValues);
}
}
public override async Task GenerateAsync(InternalEntityEntry entry, CancellationToken cancellationToken = default(CancellationToken))
{
var entityEntry = new EntityEntry(entry);
foreach (var property in FindGeneratingProperties(entry))
{
var valueGenerator = GetValueGenerator(entry, property);
SetGeneratedValue(entry, property, await valueGenerator.NextAsync(entityEntry, cancellationToken), valueGenerator.GeneratesTemporaryValues);
}
}
static IEnumerable<IProperty> FindPropagatingProperties(InternalEntityEntry entry)
{
return entry.EntityType.GetProperties().Where(property => property.IsForeignKey());
}
static IEnumerable<IProperty> FindGeneratingProperties(InternalEntityEntry entry)
{
return entry.EntityType.GetProperties().Where(property => property.RequiresValueGenerator());
}
ValueGenerator GetValueGenerator(InternalEntityEntry entry, IProperty property)
{
return valueGeneratorSelector.Select(property, property.IsKey() ? property.DeclaringEntityType : entry.EntityType);
}
static void SetGeneratedValue(InternalEntityEntry entry, IProperty property, object generatedValue, bool isTemporary)
{
if (generatedValue == null) return;
entry[property] = generatedValue;
if (isTemporary)
entry.MarkAsTemporary(property, true);
}
}
}
然后在您的DbContext 派生类中覆盖OnConfiguring 并添加以下行:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// ...
optionsBuilder.UseEF6CompatibleValueGeneration();
}
就是这样 - 问题解决了。