C# Can';t使用实体框架删除行

C# Can';t使用实体框架删除行,c#,entity-framework,concurrency,C#,Entity Framework,Concurrency,尝试使用实体框架删除行时遇到问题。 它说我有并发问题,但我不明白为什么会这样 using (AppHost_DataHubEntities db = new AppHost_DataHubEntities()) { DateTime tooOld = (DateTime.Now - HISTORY_TIME_SPAN); var asd = db.FromDataHub.RemoveRange(db.FromDataHub.Where(x => x.DateTime <

尝试使用实体框架删除行时遇到问题。 它说我有并发问题,但我不明白为什么会这样

using (AppHost_DataHubEntities db = new AppHost_DataHubEntities())
{
    DateTime tooOld = (DateTime.Now - HISTORY_TIME_SPAN);
    var asd = db.FromDataHub.RemoveRange(db.FromDataHub.Where(x => x.DateTime < tooOld));
    db.SaveChanges();
}
ERD的屏幕截图:

复制项目:

  • 根目录中的SQL安装脚本
  • 使用了sqlexpress
  • .NET版本无关紧要(使用4.5、4.6和4.7测试)

我以前遇到过这个问题,下面的信息对我很有帮助

我建议您遵循
DbContext
的用法,并在执行
.RemoveRange
之前查看是否对实体进行了更改

由于您每次(似乎)都在使用新的AppHost\u DataHubEntities,因此在调用
.RemoveRange
之前,对Entities的更改可能发生在代码中的另一个
AppHost\u DataHubEntities
实例中

因此,示例中的上下文不知道在另一个
AppHost\u DataHubEntities
实例中所做的更改

它告诉你的是,在你从 数据库,当您保存更改时,其他人已更改 数据(这意味着当你去保存它时,实际上得到了0行) 更新)。在SQL术语中,他们的update查询的where子句包含 行中每个字段的原始值,如果影响0行 它知道出了什么问题


来源:

有几件事需要尝试,评论太多了,所以:

尝试删除单个“旧”项目:

这段代码基本上是过火了,已经很晚了,但应该能给出想法。对于潜在的大型实体,我会考虑一个特定于此的有界上下文,其中为该上下文注册的定义为“OffDATA集线器”的实体仅由ID列组成。(在这种情况下,您可以将其简化为批量读取和删除。本示例所做的是执行一个查询,只返回相关的ID列(假定为PointId和DateTime)并从中填充分离的实体。然后以500个批次打开一个新的DbContext,附加该实体,将其修改状态设置为deleted,然后保存该批次。这是为了防止在DbContext实例中跟踪大量实体,以防代码需要删除大量行。同样,我的第一个偏好是在数小时后在数据库服务器上使用定时维护作业,但这可能会给您一些跟踪问题的想法

更新:您需要更新您的示例,以提供一个完整且可重复性最低的示例。我已根据您提供的内容设置了一个架构,但无法使用EF重现问题:

实体:

[Table("Points")]
public class Point
{
    [Key]
    public int PointId { get; set; }
    public string PointName { get; set; }
    public bool Collect { get; set; }

    public virtual ICollection<FromDataHub> FromDataHubs { get; set; } = new List<FromDataHub>();
    public virtual ICollection<ToDataHub> ToDataHubs { get; set; } = new List<ToDataHub>();
}

[Table("FromDataHub")]
public class FromDataHub
{
    [Key, Column(Order = 0), ForeignKey("Point")]
    public int PointId { get; set; }
    [Key, Column(Order = 1)]
    public DateTime DateTime { get; set; }
    [Key, Column(Order = 2)]
    public int Value { get; set; }

    public virtual Point Point { get; set; }
}

[Table("ToDataHub")]
public class ToDataHub
{
    [Key, Column(Order = 0), ForeignKey("Point")]
    public int PointId { get; set; }
    [Key, Column(Order = 1)]
    public DateTime DateTime { get; set; }

    public virtual Point Point { get; set; }
}
我的模式

USE [Spikes]
GO
/****** Object:  Table [dbo].[FromDataHub]    Script Date: 25/11/2020 8:50:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FromDataHub](
    [PointId] [int] NOT NULL,
    [DateTime] [datetime] NOT NULL,
    [Value] [float] NOT NULL,
 CONSTRAINT [PK_FromDataHub_1] PRIMARY KEY CLUSTERED 
(
    [PointId] ASC,
    [DateTime] 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
/****** Object:  Table [dbo].[Point]    Script Date: 25/11/2020 8:50:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Point](
    [PointId] [int] NOT NULL,
    [PointName] [nvarchar](20) NOT NULL,
    [Collect] [bit] NOT NULL,
 CONSTRAINT [PK_Points] PRIMARY KEY CLUSTERED 
(
    [PointId] 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
/****** Object:  Table [dbo].[ToDataHub]    Script Date: 25/11/2020 8:50:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ToDataHub](
    [PointId] [int] NOT NULL,
    [Value] [float] NOT NULL,
 CONSTRAINT [PK_ToDataHub_1] PRIMARY KEY CLUSTERED 
(
    [PointId] 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
ALTER TABLE [dbo].[Point] ADD  CONSTRAINT [DF_Points_Collect]  DEFAULT ((1)) FOR [Collect]
GO
ALTER TABLE [dbo].[FromDataHub]  WITH CHECK ADD  CONSTRAINT [FK_FromDataHub_Points] FOREIGN KEY([PointId])
REFERENCES [dbo].[Point] ([PointId])
GO
ALTER TABLE [dbo].[FromDataHub] CHECK CONSTRAINT [FK_FromDataHub_Points]
GO
ALTER TABLE [dbo].[ToDataHub]  WITH CHECK ADD  CONSTRAINT 
[FK_ToDataHub_Point] FOREIGN KEY([PointId])
REFERENCES [dbo].[Point] ([PointId])
GO
ALTER TABLE [dbo].[ToDataHub] CHECK CONSTRAINT [FK_ToDataHub_Point]
GO
两者中的数据相同。我没有更改的唯一架构差异是PointName的数据类型/大小。我对Collect值也有默认约束。原始架构的更改基本上是将Point ID PK和FKs从“ID”和“Point”更改为“PointId”在这两种情况下,最初我的模式没有声明FKs

我要注意的一点是,我无法让您的EDMX开箱即用。我注意到它声明的实体缺少实体的任何键或FK声明。我必须手动添加这些声明并禁用CodeFirst断言:

public AppHost_DataHubEntities : base("name=AppHost_DataHubEntities")
{
    Database.SetInitializer<AppHost_DataHubEntities>(null);
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //throw new UnintentionalCodeFirstException();
    modelBuilder.Entity<Point>()
        .ToTable("Point")
        .HasKey(x => x.PointId)
        .HasMany(x => x.FromDataHub)            
        .WithRequired(x => x.Point)
        .HasForeignKey(x => x.PointId);
    //modelBuilder.Entity<Point>()
    //    .HasKey(x => x.ID)
    //    .HasOptional(x => x.ToDataHub)
    //    .WithRequired(x => x.Point1);

    modelBuilder.Entity<FromDataHub>()
        .ToTable("FromDataHub")
        .HasKey(x => new { x.PointId, x.DateTime });

    modelBuilder.Entity<ToDataHub>()
        .ToTable("ToDataHub")
        .HasKey(x => new { x.PointId });

    }
公共AppHost\u DataHubEntities:base(“name=AppHost\u DataHubEntities”) { Database.SetInitializer(null); } 模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder) { //抛出新代码FirstException(); modelBuilder.Entity() .ToTable(“点”) .HasKey(x=>x.PointId) .HasMany(x=>x.FromDataHub) .WithRequired(x=>x.Point) .HasForeignKey(x=>x.PointId); //modelBuilder.Entity() //.HasKey(x=>x.ID) //.has可选(x=>x.ToDataHub) //.WithRequired(x=>x.Point1); modelBuilder.Entity() .ToTable(“FromDataHub”) .HasKey(x=>new{x.PointId,x.DateTime}); modelBuilder.Entity() .ToTable(“ToDataHub”) .HasKey(x=>new{x.PointId}); } 测试代码:

using (var context = new SoDbContext())
{
    DateTime tooOld = DateTime.Now - new TimeSpan(0, 15, 0);
    var items = context.FromDataHubs.Where(x => x.DateTime < tooOld).ToList();
    //db.FromDataHub.RemoveRange(items);
    context.FromDataHubs.Remove(items.First());
    context.SaveChanges();
}
使用(var context=new SoDbContext())
{
DateTime tooOld=DateTime.Now-newtimespan(0,15,0);
var items=context.FromDataHubs.Where(x=>x.DateTime
我还将DbContext上的初始值设定项设置为null并删除了迁移,但错误仍然存在于测试数据库中。因此,如果我将应用程序的配置指向数据库,则会出现错误。如果我将其指向“Spikes”数据库,则它将毫无问题地运行。我以前的单元测试也是如此


我唯一能建议的是避免EDMX&Code第一代,并手动创建所需的模式,将EF实体映射到它。在生成的模式中似乎有一些微妙的东西,奇怪的是,在为表生成的SQL中,或者在DB级别,当您说“行的状态”时,这些东西并不明显,您是指内存中对象的状态还是数据库中行的状态?我是指调用db.Entry(xy)时.State.Entity对象中的值加载到哪里?您正在创建数据库的新实例,除非连接字符串从数据库中获取数据,否则您的对象是空的。检查数据库对象以确定是否有数据。@jdweng我有值。当我将.Where子句放在外部时,我看到所有需要删除的值d、 savechanges在实体模型中需要有四个命令:Select、Update、Delete、Insert。该模型缺少这些方法。它们应该在模型中自动创建。请参阅:实际上,所有操作都是在同一个DbContext中完成的。我只是从示例中去掉了不必要的内容,以便尽可能容易理解没有任何东西可以访问我的数据库
List<FromDataHub> itemsToClean = new List<FromDataHub>();
using(var context = new AppHost_DataHubEntities())
{
    itemsToClean = context.FromDataHub
        .Where(x => x.DateTime < tooOld)
        .Select(x => new FromDataHub { PointId = x.PointId, DateTime = x.DateTime })
        .ToList();
}

const int batchSize = 500;
int batchCount = 1;
var batch = itemsToClean.Take(batchSize);
while(batch.Any())
{
    using(var context = new AppHost_DataHubEntities())
    {
        foreach(var item in batch)
        {
            context.FromDataHub.Attach(item);
            context.Entity(item).EntityState = EntityState.Deleted;
        }
        context.SaveChanges();
    }
    batch = itemsToClean.Skip(++batchCount).Take(batchSize);
}
[Table("Points")]
public class Point
{
    [Key]
    public int PointId { get; set; }
    public string PointName { get; set; }
    public bool Collect { get; set; }

    public virtual ICollection<FromDataHub> FromDataHubs { get; set; } = new List<FromDataHub>();
    public virtual ICollection<ToDataHub> ToDataHubs { get; set; } = new List<ToDataHub>();
}

[Table("FromDataHub")]
public class FromDataHub
{
    [Key, Column(Order = 0), ForeignKey("Point")]
    public int PointId { get; set; }
    [Key, Column(Order = 1)]
    public DateTime DateTime { get; set; }
    [Key, Column(Order = 2)]
    public int Value { get; set; }

    public virtual Point Point { get; set; }
}

[Table("ToDataHub")]
public class ToDataHub
{
    [Key, Column(Order = 0), ForeignKey("Point")]
    public int PointId { get; set; }
    [Key, Column(Order = 1)]
    public DateTime DateTime { get; set; }

    public virtual Point Point { get; set; }
}
modelBuilder.Entity<Point>()
    .HasMany(x => x.FromDataHubs)
    .WithRequired(x => x.Point);

modelBuilder.Entity<Point>()
    .HasMany(x => x.ToDataHubs)
    .WithRequired(x => x.Point); 
using (var context = new TestDbContext())
{
    DateTime date = DateTime.Today.AddMonths(-6);
    var itemsToDelete = context.FromDataHubs.Where(x => x.DateTime < date);
    context.FromDataHubs.RemoveRange(itemsToDelete);
    context.SaveChanges();
}
USE [StackExample]
GO
/****** Object:  Table [dbo].[FromDataHub]    Script Date: 25/11/2020 8:50:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FromDataHub](
    [PointId] [int] NOT NULL,
    [DateTime] [datetime] NOT NULL,
    [Value] [float] NOT NULL,
 CONSTRAINT [PK_FromDataHub] PRIMARY KEY CLUSTERED 
(
    [PointId] ASC,
    [DateTime] 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
/****** Object:  Table [dbo].[Point]    Script Date: 25/11/2020 8:50:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Point](
    [PointId] [int] IDENTITY(1,1) NOT NULL,
    [PointName] [varchar](255) NOT NULL,
    [Collect] [bit] NOT NULL,
 CONSTRAINT [PK_Point] PRIMARY KEY CLUSTERED 
(
    [PointId] 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
/****** Object:  Table [dbo].[ToDataHub]    Script Date: 25/11/2020 8:50:04 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ToDataHub](
    [PointId] [int] NOT NULL,
    [Value] [float] NOT NULL,
 CONSTRAINT [PK_ToDataHub] PRIMARY KEY CLUSTERED 
(
    [PointId] 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
ALTER TABLE [dbo].[FromDataHub]  WITH CHECK ADD  CONSTRAINT [FK_FromDataHub_Point] FOREIGN KEY([PointId])
REFERENCES [dbo].[Point] ([PointId])
GO
ALTER TABLE [dbo].[FromDataHub] CHECK CONSTRAINT [FK_FromDataHub_Point]
GO
ALTER TABLE [dbo].[ToDataHub]  WITH CHECK ADD  CONSTRAINT [FK_ToDataHub_Point] FOREIGN KEY([PointId])
REFERENCES [dbo].[Point] ([PointId])
GO
ALTER TABLE [dbo].[ToDataHub] CHECK CONSTRAINT [FK_ToDataHub_Point]
GO
USE [Spikes]
GO
/****** Object:  Table [dbo].[FromDataHub]    Script Date: 25/11/2020 8:50:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FromDataHub](
    [PointId] [int] NOT NULL,
    [DateTime] [datetime] NOT NULL,
    [Value] [float] NOT NULL,
 CONSTRAINT [PK_FromDataHub_1] PRIMARY KEY CLUSTERED 
(
    [PointId] ASC,
    [DateTime] 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
/****** Object:  Table [dbo].[Point]    Script Date: 25/11/2020 8:50:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Point](
    [PointId] [int] NOT NULL,
    [PointName] [nvarchar](20) NOT NULL,
    [Collect] [bit] NOT NULL,
 CONSTRAINT [PK_Points] PRIMARY KEY CLUSTERED 
(
    [PointId] 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
/****** Object:  Table [dbo].[ToDataHub]    Script Date: 25/11/2020 8:50:44 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ToDataHub](
    [PointId] [int] NOT NULL,
    [Value] [float] NOT NULL,
 CONSTRAINT [PK_ToDataHub_1] PRIMARY KEY CLUSTERED 
(
    [PointId] 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
ALTER TABLE [dbo].[Point] ADD  CONSTRAINT [DF_Points_Collect]  DEFAULT ((1)) FOR [Collect]
GO
ALTER TABLE [dbo].[FromDataHub]  WITH CHECK ADD  CONSTRAINT [FK_FromDataHub_Points] FOREIGN KEY([PointId])
REFERENCES [dbo].[Point] ([PointId])
GO
ALTER TABLE [dbo].[FromDataHub] CHECK CONSTRAINT [FK_FromDataHub_Points]
GO
ALTER TABLE [dbo].[ToDataHub]  WITH CHECK ADD  CONSTRAINT 
[FK_ToDataHub_Point] FOREIGN KEY([PointId])
REFERENCES [dbo].[Point] ([PointId])
GO
ALTER TABLE [dbo].[ToDataHub] CHECK CONSTRAINT [FK_ToDataHub_Point]
GO
public AppHost_DataHubEntities : base("name=AppHost_DataHubEntities")
{
    Database.SetInitializer<AppHost_DataHubEntities>(null);
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //throw new UnintentionalCodeFirstException();
    modelBuilder.Entity<Point>()
        .ToTable("Point")
        .HasKey(x => x.PointId)
        .HasMany(x => x.FromDataHub)            
        .WithRequired(x => x.Point)
        .HasForeignKey(x => x.PointId);
    //modelBuilder.Entity<Point>()
    //    .HasKey(x => x.ID)
    //    .HasOptional(x => x.ToDataHub)
    //    .WithRequired(x => x.Point1);

    modelBuilder.Entity<FromDataHub>()
        .ToTable("FromDataHub")
        .HasKey(x => new { x.PointId, x.DateTime });

    modelBuilder.Entity<ToDataHub>()
        .ToTable("ToDataHub")
        .HasKey(x => new { x.PointId });

    }
using (var context = new SoDbContext())
{
    DateTime tooOld = DateTime.Now - new TimeSpan(0, 15, 0);
    var items = context.FromDataHubs.Where(x => x.DateTime < tooOld).ToList();
    //db.FromDataHub.RemoveRange(items);
    context.FromDataHubs.Remove(items.First());
    context.SaveChanges();
}