Entity framework 6.1 проверьте, не прикреплен ли он, затем прикрепите сбой

Я пытаюсь что-то сделать, и вот "демонстрация", очень простой пример. (эта демонстрация не имеет смысла, но дает общее представление о том, что я пытаюсь сделать)

я прокомментировал то, что я пробовал

есть ли способ сделать это без создания нового контекста?

это первая база данных на сервере sql

код c #

using System;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //remove then add it back, without select from the db
            using (var db = new testing())
            {
                var lookup = new edmx.LookupTable() { LookupId = 1 };

                var main = new edmx.MainTable() { MainId = 10 };
                main.LookupTables.Add(lookup);

                db.LookupTables.Attach(lookup);

                db.MainTables.Attach(main);

                main.LookupTables.Remove(lookup);

                db.SaveChanges();

                //imagine this is a loop from n to m and it happen that you have to add back something that you just deleted
                lookup = new edmx.LookupTable() { LookupId = 1 };

                //crash if nothing

                //db.Entry(lookup).State = EntityState.Unchanged; //crash
                //db.LookupTables.Attach(lookup); //crash

                if (!db.context.IsAttachedTo(lookup))
                {
                    //db.Entry(lookup).State = EntityState.Unchanged; //crash
                    //db.LookupTables.Attach(lookup); //crash
                }

                bool isDetached = db.Entry(lookup).State == EntityState.Detached;
                if (isDetached)
                {
                    //db.Entry(lookup).State = EntityState.Unchanged; //crash
                    //db.LookupTables.Attach(lookup); //crash
                }

                main.LookupTables.Add(lookup);

                db.SaveChanges();
            }

            Console.ReadKey();
        }
    }

    public partial class testing : edmx.testingEntities
    {
        public testing()
            : base()
        {
            this.Database.Log = x => System.Diagnostics.Debug.Write(x);
        }
        public ObjectContext context
        {
            get { return (this as IObjectContextAdapter).ObjectContext; }
        }
    }

    public static class helper
    {
        public static bool IsAttachedTo(this ObjectContext context, object entity)
        {
            ObjectStateEntry entry;
            if (context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry))
            {
                return (entry.State != EntityState.Detached);
            }
            return false;
        }
    }
}

SQL скрипт

USE [testing]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[LookupTable](
    [LookupId] [int] NOT NULL,
 CONSTRAINT [PK_LookupTable] PRIMARY KEY CLUSTERED 
(
    [LookupId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MainTable](
    [MainId] [int] NOT NULL,
 CONSTRAINT [PK_MainTable] PRIMARY KEY CLUSTERED 
(
    [MainId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MainTable_LookupTable](
    [MainId] [int] NOT NULL,
    [LookupId] [int] NOT NULL,
 CONSTRAINT [PK_MainTable_LookupTable] PRIMARY KEY CLUSTERED 
(
    [MainId] ASC,
    [LookupId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[LookupTable] ([LookupId]) VALUES (1)
GO
INSERT [dbo].[MainTable] ([MainId]) VALUES (10)
GO
INSERT [dbo].[MainTable_LookupTable] ([MainId], [LookupId]) VALUES (10, 1)
GO
ALTER TABLE [dbo].[MainTable_LookupTable]  WITH CHECK ADD  CONSTRAINT [FK_MainTable_LookupTable_LookupTable] FOREIGN KEY([LookupId])
REFERENCES [dbo].[LookupTable] ([LookupId])
GO
ALTER TABLE [dbo].[MainTable_LookupTable] CHECK CONSTRAINT [FK_MainTable_LookupTable_LookupTable]
GO
ALTER TABLE [dbo].[MainTable_LookupTable]  WITH CHECK ADD  CONSTRAINT [FK_MainTable_LookupTable_MainTable] FOREIGN KEY([MainId])
REFERENCES [dbo].[MainTable] ([MainId])
GO
ALTER TABLE [dbo].[MainTable_LookupTable] CHECK CONSTRAINT [FK_MainTable_LookupTable_MainTable]
GO

решение, в моем случае, это код

for (var i = 1; i < 3; ++i)
{
    lookup = db.LookupTables.Local.FirstOrDefault(x => x.LookupId == i);

    if (lookup == null)
    {
        lookup = new edmx.LookupTable() { LookupId = i };
        db.LookupTables.Attach(lookup);
    }

    main.LookupTables.Add(lookup);
}

person Fredou    schedule 29.03.2014    source источник


Ответы (1)


Экземпляр поиска (с идентификатором 1) все еще прикреплен к EF, вызываемое вами Remove просто удаляет связь между main (10) и lookup (1).

Когда вы снова создаете экземпляр поиска, это другой экземпляр в .NET, но для базы данных / EF это фактически дубликат.

Вам следует либо повторно использовать предыдущий экземпляр поиска, либо использовать DbSet's Local, чтобы найти его снова.

person XIU    schedule 29.03.2014
comment
спасибо, я обновил свой вопрос своим решением, используя ваше предложение, которое хорошо работает - person Fredou; 29.03.2014