【问题标题】:Entity Framework 4.1 - Error in many-to-many relationship data when insert data that removed previouslyEntity Framework 4.1 - 插入先前删除的数据时,多对多关系数据中的错误
【发布时间】:2012-01-13 09:49:31
【问题描述】:

场景:

我有 3 个表,它们形成了多对多关系:

Agent (AgentID (PK), AgentName)
AgentChannel (AgentID (PK), ChannelID (PK))
Channel (ChannelID (PK), ChannelName)

我不想在 Agent 和 Channel 表中添加/删除任何记录,而只想修改 AgentChannel 表。

我正在使用 EF 4.1、POCO 和自我跟踪实体。所有处理数据库的代码都包含在 WCF 层中,我称之为服务器端代码,我只能控制客户端代码中记录的添加/删除。

例如: 我有一个代理记录,有多个通道记录。我可以通过这种方式将现有频道链接到代理:

var channel = new Channel { ChannelID = 1 };
channel.MarkAsUnchanged();
agent.Channels.Add(channel);
// This will add new entry to AgentChannel table, but no change on Agent and Channel tables

我也可以通过这种方式删除频道与代理的链接:

var tempChannels = agent.Channels.ToList();
var channelToDelete = tempChannels.FirstOrDefault(c => c.ChannelID == 3);
agent.Channels.Remove(channelToDelete);
// This will remove the entry in AgentChannel, but no change on Agent and Channel tables.



我的问题:
如果我删除了一个频道,并将一个与之前删除的频道具有相同 ChannelID 的新频道添加回 agent.Channels 集合,我将收到此错误:

AcceptChanges 无法继续,因为对象的键值与 ObjectStateManager 中的另一个对象冲突。

演示示例代码:

        //
        // I not able to call ObjectContext here because it was reside in server side.
        //

        //
        // This is client side code
        //
        var tempChannels = agent.Channels.ToList();
        var channelToDelete = tempChannels.FirstOrDefault(c => c.ChannelID == 3);

        // remove channel 3
        agent.Channels.Remove(channelToDelete);

        var channel = new Channel { ChannelID = 3 };
        channel.MarkAsUnchanged();

        // Add back channel 3
        agent.Channels.Add(channel);

        //
        // This is server side code (WCF layer)
        //
        try
        {
            using (var ctx = new testEntities())
            {
                ctx.ApplyChanges("Agents", agent); // <-- ERROR happen here
                ctx.SaveChanges();
            }
        }
        catch (Exception)
        {
            throw;
        }

然后我收到异常消息:

    System.InvalidOperationException was unhandled
  Message=AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Objects.ObjectStateManager.FixupKey(EntityEntry entry)
       at System.Data.Objects.EntityEntry.AcceptChanges()
       at System.Data.Objects.EntityEntry.ChangeObjectState(EntityState requestedState)
       at System.Data.Objects.ObjectStateManager.ChangeObjectState(Object entity, EntityState entityState)
       at TestManyToMany.SelfTrackingEntitiesContextExtensions.ChangeEntityStateBasedOnObjectState(ObjectContext context, IObjectWithChangeTracker entity) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Model1.Context.Extensions.cs:line 728
       at TestManyToMany.SelfTrackingEntitiesContextExtensions.HandleEntity(ObjectContext context, EntityIndex entityIndex, RelationshipSet allRelationships, IObjectWithChangeTracker entity) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Model1.Context.Extensions.cs:line 596
       at TestManyToMany.SelfTrackingEntitiesContextExtensions.ApplyChanges[TEntity](ObjectContext context, String entitySetName, TEntity entity) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Model1.Context.Extensions.cs:line 84
       at TestManyToMany.Program.Main(String[] args) in F:\MyFile\Development\Temp\TestManyToMany\TestManyToMany\Program.cs:line 53
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

我希望我说清楚。这是我现在面临的唯一问题,我没有想法。

非常感谢。

-


-

更新 - 回答

根据 Ladislav Mrnka 的评论,我在完成测试后得到了答案。

基本上你需要添加回之前删除的同一个实体,没有其他实体,因为这会给你上面相同的错误。

这是客户端的示例代码,服务器端无需更改:

        int channelId = 1;

        var tempChannels = agent.Channels.ToList();
        var channelToDelete = tempChannels.FirstOrDefault(c => c.ChannelID == channelId);

        // remove channel 1
        agent.Channels.Remove(channelToDelete);


        //var channel = _allChannels.First(c => c.ChannelID == channelId);
        //agent.Channels.Add(channel);           <-- This line will give you ERROR because the channel entity is from _allChannels, but not from agent.Channels

        // Add back channel 1
        agent.Channels.Add(channelToDelete); //  <-- This is CORRECT

【问题讨论】:

    标签: entity-framework-4.1 many-to-many ef-code-first


    【解决方案1】:

    这是不允许的操作。如果您删除了频道并想再次添加它,则不得创建新实例。你必须使用旧的并且只改变它的状态。主要规则是每个具有唯一键的实体只能声明一次。您的代码导致两个实例具有相同的键 = 错误。

    【讨论】:

    • 谢谢你,它现在可以工作了!!我想我错过了对来自父实体的实体的测试!!我将在我的问题中更新我的发现。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2018-06-24
    • 2020-11-05
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多