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();
}