我正在学习。
我在.netcoreapp 2.1中使用Microsoft.EntityFrameworkCore
,关键是要通过API公开静态数据。
当前,我将数据存储在json对象中。让示例保持简单,我正在尝试公开一盘三明治和这些三明治的配料。三明治有各种类型(百吉饼,长面包,短面包等)
首先,我不完全确定使用EF是正确的工具,但是由于稍后我必须管理这些项目(能够点菜),所以我从那里开始。如果有更好的工具供我使用,我现在不禁听到,但是现在我的问题是使用EF公开它。
我正在读取应用程序中经过硬编码的json,并将其用作我的DbContext
的起点。我只是在构造函数中反序列化它,然后将其加载到我的上下文对象中,然后通过API将其公开。在todo-list模板项目中就像魅力一样。
这是它的外观,我只是添加了更多的DBSet以满足我的需求
public class EatupContext : DbContext
{
public DbSet<FoodType> Types { get; set; }
public DbSet<Ingredient> Ingredients { get; set; }
public DbSet<FoodItem> Items { get; set; }
}
FoodType
是带有ID和名称的int
。与Ingredients
相同。
物品是三明治,看起来像这样
public class FoodItem
{
public int Id { get; set; }
public string Name { get; set; }
public FoodType Type { get; set; }
public IEnumerable<Ingredient> Ingredients { get; set; }
}
在我正在读取的json(映射方式与c#对象相似)中,所有对象的所有id均从0开始。因此Types
从0到7,从0到105的成分,从0到60的食品。
这会导致实体框架的ID跟踪问题,因为存在多个具有相同ID的对象。即使它们位于不同的DBSets
中,这也让我感到困惑。根据我的理解(有缺陷?),两个表(DBSet?)可以具有重复的ID。我可以有一个类型为0,成分为0、1、2和3的三明治ID0。看来 more 会让我感到困惑,类型从0到7,然后成分从8到113,以及从114到174的三明治。从数据库角度来看,这对我来说真的很奇怪。
这是我得到的确切错误:
An unhandled exception occurred while processing the request.
InvalidOperationException: The instance of entity type 'Ingredient' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.
When attaching existing entities, ensure that only one entity instance with a given key value is attached.
Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap<TKey>.ThrowIdentityConflict(InternalEntityEntry entry)
具有以下stacktrace:
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap<TKey>.ThrowIdentityConflict(InternalEntityEntry entry)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap<TKey>.Add(TKey key, InternalEntityEntry entry, bool updateDuplicate)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, bool acceptChanges)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, bool acceptChanges, Nullable<EntityState> forceStateWhenUnknownKey)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode node, bool force)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph<TState>(EntityEntryGraphNode node, TState state, Func<EntityEntryGraphNode, TState, bool> handleNode)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph<TState>(EntityEntryGraphNode node, TState state, Func<EntityEntryGraphNode, TState, bool> handleNode)
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState entityState, bool forceStateWhenUnknownKey)
Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState)
Microsoft.EntityFrameworkCore.DbContext.SetEntityStates(IEnumerable<object> entities, EntityState entityState)
Microsoft.EntityFrameworkCore.DbContext.UpdateRange(IEnumerable<object> entities)
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.UpdateRange(IEnumerable<TEntity> entities)
EatUp.Backend.Controllers.EatupController..ctor(EatupContext context) in EatupController.cs
+
_context.Items.UpdateRange(completeModel.Items);
lambda_method(Closure , IServiceProvider , object[] )
Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider+<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider+<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
这会在控制器中的以下代码中发生:
private readonly EatupContext _context;
public EatupController(EatupContext context)
{
_context = context;
var completeModel = JsonConvert.DeserializeObject<EatUpDataModel>(EatUpDataSet.Complete);
_context.Items.UpdateRange(completeModel.Items); //fails here
_context.Types.UpdateRange(completeModel.Types);
_context.Ingredients.UpdateRange(completeModel.Ingredients);
_context.SaveChanges();
}
如果我使用AddRange
,它也会失败;我正在使用Update
,所以我不必检查集合是否为空,我只是用json中的最新数据将其擦除。
我不确定应该采取什么方法,我真的不想手动编辑json,但是我看不到如何告诉EF这些是我自己以外的独立对象已经在做。
编辑:
我手动编辑了所有ID,使其只有唯一的ID,但仍然出现错误。
ID出现两次的唯一时间是在不同的三明治中使用相同的成分时,这应该可以接受。
现在我200%感到困惑,我想念什么?
答案 0 :(得分:0)
通常,您不需要告诉EF这些是单独的对象。它应该解决。您可以复制并粘贴您的迁移吗?