使用 EF5 将新实体保存到数据库时,会保存 ID 为 0 的记录。数据库有一个标识列,从 1 开始,计数为 1。
当我重新创建特定表时,所有问题都消失了。但我不想一直在我的生产环境中重新创建表。
因为我不是 SQL 专家。有什么方法可以解决这个问题吗?我们正在使用 MSSQL2005(订购了 SQL2012,但在它出现之前我无法使用它,并且需要一些时间将旧数据库迁移到新数据库)。
//Database creation script
/* [Queue].[DirectDebitOrder] */
CREATE TABLE [Queue].[BookingExportTask](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[DirectDebitRequestID] [bigint] NOT NULL,
[Type] [nvarchar](50) NOT NULL,
[Step] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Queue_BookingExportTask] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY];
/* Foreign Keys */
ALTER TABLE [Queue].[BookingExportTask] WITH CHECK ADD CONSTRAINT [FK_Queue_BookingExportTask_Queue_BookingExportTaskStepEnum] FOREIGN KEY([Step]) REFERENCES [Queue].[BookingExportTaskStepEnum] ([Name]);
ALTER TABLE [Queue].[BookingExportTask] CHECK CONSTRAINT [FK_Queue_BookingExportTask_Queue_BookingExportTaskStepEnum];
ALTER TABLE [Queue].[BookingExportTask] WITH CHECK ADD CONSTRAINT [FK_Queue_BookingExportTask_Queue_BookingExportTaskTypeEnum] FOREIGN KEY([Type]) REFERENCES [Queue].[BookingExportTaskTypeEnum] ([Name]);
ALTER TABLE [Queue].[BookingExportTask] CHECK CONSTRAINT [FK_Queue_BookingExportTask_Queue_BookingExportTaskTypeEnum];
ALTER TABLE [Queue].[BookingExportTask] WITH CHECK ADD CONSTRAINT [FK_Queue_BookingExportTask_Finance_DirectDebitRequest] FOREIGN KEY([DirectDebitRequestID]) REFERENCES [Finance].[DirectDebitRequest] ([ID])
ALTER TABLE [Queue].[BookingExportTask] CHECK CONSTRAINT [FK_Queue_BookingExportTask_Finance_DirectDebitRequest];
//C# Code for saving Entities
/// <summary>
/// Saves the data in the <see cref="ILoadableBookingExportTask"/> to the <paramref name="entityContext"/>
/// </summary>
/// <param name="entityContext">The <see cref="DBContext"/> context to save the <see cref="ILoadableBookingExportTask"/> to.</param>
/// <param name="source">The <see cref="ILoadableBookingExportTask"/> to save.</param>
/// <returns>The <see cref="BookingExportTask"/> that holds the actually stored values.</returns>
public static BookingExportTask Save(this DBContext entityContext, ILoadableBookingExportTask source)
{
if (source == null) { return null; }
return source.SaveTo(entityContext.BookingExportTask.EnsureExists(source), entityContext);
}
/// <summary>
/// Helper. Finds existing instance or creates a new instance of <typeparamref name="TEntityType"/> which is immediately added to the <see cref="dbSet{TEntityType}"/> as well.
/// </summary>
/// <typeparam name="TEntityType">The type of the entity to check.</typeparam>
/// <param name="dbSet">The database collection for the entity.</param>
/// <param name="entity">The <see cref="IEntity"/> to find.</param>
/// <returns>The existing or newly created <typeparamref name="TEntityType"/>.</returns>
public static TEntityType EnsureExists<TEntityType>(this DbSet<TEntityType> dbSet, IEntity entity)
where TEntityType : class, IEntity, new()
{
if (entity == null) { return default(TEntityType); }
return dbSet.EnsureExists(entity.ID);
}
/// <summary>
/// Helper. Finds existing instance or creates a new instance of <typeparamref name="TEntityType"/> which is immediately added to the <see cref="dbSet{TEntityType}"/> as well.
/// </summary>
/// <typeparam name="TEntityType">The type of the entity to check.</typeparam>
/// <param name="dbSet">The collection to check for existance of the entity.</param>
/// <param name="id">The ID of the entity to find.</param>
/// <returns>The existing or newly created <typeparamref name="TEntityType"/>.</returns>
public static TEntityType EnsureExists<TEntityType>(this DbSet<TEntityType> dbSet, long id)
where TEntityType : class, IEntity, new()
{
return dbSet.GetByID(id) ?? dbSet.New();
}
/// <summary>
/// Saves the data in the <see cref="ILoadableBookingExportTask"/> to the <paramref name="entityContext"/>
/// </summary>
/// <param name="source">The <see cref="ILoadableBookingExportTask"/> to save.</param>
/// <param name="target">The <see cref="BookingExportTask"/> to save the data to.</param>
/// <param name="entityContext">The <see cref="DBContext"/> context to save the <see cref="ILoadableBookingExportTask"/> to.</param>
/// <returns>The <see cref="BookingExportTask"/> that holds the actually stored values.</returns>
private static BookingExportTask SaveTo(this ILoadableBookingExportTask source, BookingExportTask target, DBContext entityContext)
{
if (source == null) { return target; }
Debug.WriteLine(string.Format("Saving ILoadableBookingExportTask {0} to DBContext.", target.ID));
/* copy all fields from source to target. Use SyncLinkedObject for all linked entities to ensure the saving of possible changes to the foreign entities.
* target.Field = target.Field;
* target.RelatedEntity = entityContext.SyncLinkedObject(source.RelatedEntity, source.RelatedEntity_ForeignKey);
*
* Note: It's useless to overwrite the Identity property - like target.ID. Just skip it.
*/
return target;
}
简而言之 C# 代码:
- 检查实体是否已经存在(它是一个新实体,所以否)
- 在上下文中的特定 DBSet 中创建新实体
- 将业务实体的值传递给 dbset-entity(不带 ID)
- 保存上下文
这一切都很好,直到。DB 被更改或恢复。之后,必须重新创建具有标识列的表。如果我不重新创建表,则第一个新实体将保存到 ID 0。使用 ensureExists 方法,从那一刻起,所有新实体都将覆盖现有实体,这是合乎逻辑的,因为 ID 为 0。
问题是 EF 无法识别标识列。
如果出现此问题,我使用 SQL Profiler 监控数据库。我将探查器发现的传入查询粘贴到我获取 ID 的 SQL 管理工作室中。所以看起来数据库很好。代码之前没有更改和工作(在还原数据库之前)。到目前为止,我发现的唯一解决方案是使用标识列重新创建表。之后,C# 代码无需适应即可再次工作。