c# - Entity Framework Core 在多对多上添加新条目时尝试添加旧条目
问题描述
我的EF Core 5.0.2
代码优先中存在多对多关系:
public sealed class BlipPluginDto
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string BlipPluginId { get; set; }
[Required]
public ICollection<SmartContactDto> SmartContacts { get; set; }
}
public sealed class SmartContactDto
{
[Key]
public int SmartContactId { get; set; }
[Required]
public string Identifier { get; set; }
public ICollection<BlipPluginDto> BlipPlugins { get; set; }
}
关系在 DBContext( MarketplaceDb
) 中配置为:
modelBuilder.Entity<BlipPluginDto>().HasMany(bp => bp.SmartContacts).WithMany(sc => sc.BlipPlugins);
然后我尝试将SmartContactDto
(新的或现有的)记录添加到现有的BlipPluginDto
:
public async Task<SmartContactDto> GetOrCreateSmartContactAsync(
string identifier,
CancellationToken cancellationToken) =>
await MarketplaceDb.SmartContacts
.Include(sc => sc.BlipPlugins)
.FirstOrDefaultAsync(sc => sc.Identifier == identifier, cancellationToken)
?? new SmartContactDto() { Identifier = identifier };
public async Task<bool> AddActivePluginAsync(
string smartContactIdentifier,
string blipPluginId,
CancellationToken cancellationToken = default)
{
var blipPlugin = await _blipPluginService.GetPluginByIdAsync(blipPluginId, cancellationToken);
if (blipPlugin == default)
{
return false;
}
var smartContact = await GetOrCreateSmartContactAsync(smartContactIdentifier, cancellationToken);
if (smartContact.BlipPlugins?.Any(bp => bp.BlipPluginId == blipPluginId) == true)
{
return false;
}
blipPlugin.SmartContacts.Add(smartContact);
MarketplaceDb.Update(blipPlugin);
await MarketplaceDb.SaveChangesAsync(cancellationToken);
return true;
}
_blipPluginService.GetPluginByIdAsync
: _
public async Task<BlipPluginDto> GetPluginByIdAsync(string id, CancellationToken cancellationToken = default)
{
var plugin = await MarketplaceDb.BlipPlugins
.Include(bp => bp.SmartContacts)
.FirstOrDefaultAsync(bp => bp.BlipPluginId == id, cancellationToken);
return plugin;
}
如果blipPlugin
没有smartContact
它可以正常工作( a 的第一个插入SmartContactDto
),但是当blipPlugin
已经有一个smartContact
实体告诉我我正在尝试在 Join 表上添加一个具有相同 id 的项目时(由EF 核心)。
假设我正在尝试将一个SmartContactDto
with添加SmartContactId = 68
到一个已经有一个的 withBlipPluginDto
我得到以下内部异常:BlipPluginId = "foo"
SmartContactDto
SmartContactId = 12
Violation of PRIMARY KEY constraint 'PK_BlipPluginDtoSmartContactDto'. Cannot insert duplicate key in object 'Marketplace.BlipPluginDtoSmartContactDto'. The duplicate key value is (foo, 12)
我尝试了许多不同的方法,但我总是坚持这一点,即使我做相反的事情(创建并保存一个新的smartContact
然后添加blipPlugin
到smartContact
.
解决方案
所有这些工作都需要在同一个 MarketplaceDb 上下文(工作单元)中完成。
我怀疑您的 GetOrCreateSmartContact 使用的 DbContext 与您在 _blipPlugInService 中检索原始插件的位置不同,然后您在最后对其进行更新。
因此,当您添加由 GetOrCreateSmartContact 找到的现有 SmartContact 时,它来自与您执行最终结果的上下文不同的上下文
blipPlugin.SmartContacts.Add(smartContact);
MarketplaceDb.Update(blipPlugin);
await MarketplaceDb.SaveChangesAsync(cancellationToken);
结果,这个最终上下文没有跟踪您检索到的 SmartContact,因此认为它是一个新上下文。
总之,当执行这样的一批操作时,您必须使用 DbContext for Entity Framework 的相同实例来发挥它的魔力。
推荐阅读
- kotlin - kotlin.UninitializedPropertyAccessException:lateinit 属性 textInput 尚未初始化”
- mysql - Laravel - MySQL - 时间戳性能与布尔列?
- php - 如何在php中从数组中回显值时去掉逗号(,)
- python - 过滤数据框中的日期索引
- django - 在基于 django 类的视图(DetailView)中从 POST 方法反转
- python - 具有动态参数的 R 函数
- spring - 如何在骆驼路线中使用spring bean,在xml中定义
- javascript - 替代 lastIndexOf() 函数
- java - FunctionalInterfaces 不计算 Object 类 Method
- c# - Xamarin Forms 在启动时显示动画标签