英文:
Audit.EntityFramework: SqlException: Cannot insert explicit value for identity column
问题
Here is the translated content you requested:
- Entity Framework Core: 实体框架核心
- .NET 7: .NET 7
- SQL Server: SQL Server
Error:
在将IDENTITY_INSERT设置为OFF的情况下,无法向表'AuditLogs'插入显式值。
Info:
- Identity Insert已设置为ON
- 我的列是Identity(1,1) PRIMARY KEY
- 这是我首次实现此功能,所以可能漏掉了一些重要内容。
Program.cs setup:
private static void AuditSetup()
{
// 设置Audit.NET
Audit.Core.Configuration.DataProvider = new EntityFrameworkDataProvider()
{
DbContextBuilder = ev => new DatabaseContext(AppConfig.ConnectionString),
AuditTypeMapper = (t, ee) =>
{
var typesToAudit = new List<Type>()
{
typeof(LiveLoadLocking)
};
if (typesToAudit.Contains(t))
{
return typeof(AuditLog);
}
return null;
},
AuditEntityAction = async (evt, entry, auditEntity) =>
{
AuditLog a = (AuditLog)auditEntity;
a.AuditDate = DateTime.UtcNow;
a.UserName = evt.Environment.UserName;
a.AuditAction = entry.Action;
a.EntityType = entry.EntityType.Name;
a.EntityId = entry.PrimaryKey.FirstOrDefault().Value?.ToString();
var changes = entry.Changes;
if (changes != null)
{
a.ChangedColumns = string.Join(", ", changes.Select(c => c.ColumnName));
a.OldValues = JsonConvert.SerializeObject(changes.ToDictionary(c => c.ColumnName, c => c.OriginalValue));
a.NewValues = JsonConvert.SerializeObject(changes.ToDictionary(c => c.ColumnName, c => c.NewValue));
}
return true;
}
};
}
AuditLog:
public class AuditLog
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime AuditDate { get; set; }
public string UserName { get; set; }
public string AuditAction { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public string OldValues { get; set; }
public string NewValues { get; set; }
public string ChangedColumns { get; set; }
}
modelBuilder:
modelBuilder.Entity<AuditLog>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__AuditLog__somename");
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.AuditDate).IsRequired();
entity.Property(e => e.UserName).HasMaxLength(256);
entity.Property(e => e.AuditAction).IsRequired().HasMaxLength(50);
entity.Property(e => e.EntityType).IsRequired().HasMaxLength(128);
entity.Property(e => e.EntityId).IsRequired().HasMaxLength(128);
entity.Property(e => e.OldValues).HasColumnType("nvarchar(max)");
entity.Property(e => e.NewValues).HasColumnType("nvarchar(max)");
entity.Property(e => e.ChangedColumns).HasColumnType("nvarchar(max)");
});
我有以下上下文类:
public partial class DFDBContext : Audit.EntityFramework.AuditDbContext
public partial class DatabaseContext : DFDBContext
保存逻辑示例(结构可能不完美,我知道):
public static void UnlockLoad(string df)
{
using (var context = new DatabaseContext(AppConfig.ConnectionString))
{
LiveLoadLocking loadLock = context.LiveLoadLockings
.SingleOrDefault(x => x.somefield == somenumber);
loadLock.IsLocked = false;
loadLock.LockedBy = "";
loadLock.LastUpdated = DateTime.Now;
if (context.SaveChanges() <= 0) { throw new ContextFailedToSaveException("项目未保存或更新到数据库。", loadLock); }
}
}
我似乎无法解决此身份错误。有人有任何建议吗?我在许多表上都设置了相同的身份,并且以前从未遇到过此错误,因此我认为Audit正在尝试将身份本身插入到AuditLog表中?是否有任何解决方法或停止尝试执行此操作的方法?
谢谢!
英文:
- Entity Framework Core
- .NET 7
- SQL Server
Error:
Cannot insert explicit value for identity column in table 'AuditLogs' when IDENTITY_INSERT is set to OFF.
Info:
- Identity Insert is set to ON
- My Column is Identity(1,1) PRIMARY KEY
- This is my first time implementing this, so I could be missing something large that I'm not seeing.
Program.cs setup:
private static void AuditSetup()
{
// Set up Audit.NET
Audit.Core.Configuration.DataProvider = new EntityFrameworkDataProvider()
{
DbContextBuilder = ev => new DatabaseContext(AppConfig.ConnectionString),
AuditTypeMapper = (t, ee) =>
{
var typesToAudit = new List<Type>()
{
typeof(LiveLoadLocking)
};
if (typesToAudit.Contains(t))
{
return typeof(AuditLog);
}
return null;
},
AuditEntityAction = async (evt, entry, auditEntity) =>
{
AuditLog a = (AuditLog)auditEntity;
a.AuditDate = DateTime.UtcNow;
a.UserName = evt.Environment.UserName;
a.AuditAction = entry.Action;
a.EntityType = entry.EntityType.Name;
a.EntityId = entry.PrimaryKey.FirstOrDefault().Value?.ToString();
var changes = entry.Changes;
if (changes != null)
{
a.ChangedColumns = string.Join(", ", changes.Select(c => c.ColumnName));
a.OldValues = JsonConvert.SerializeObject(changes.ToDictionary(c => c.ColumnName, c => c.OriginalValue));
a.NewValues = JsonConvert.SerializeObject(changes.ToDictionary(c => c.ColumnName, c => c.NewValue));
}
return true;
}
};
}
AuditLog:
public class AuditLog
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime AuditDate { get; set; }
public string UserName { get; set; }
public string AuditAction { get; set; }
public string EntityType { get; set; }
public string EntityId { get; set; }
public string OldValues { get; set; }
public string NewValues { get; set; }
public string ChangedColumns { get; set; }
}
modelBuilder:
modelBuilder.Entity<AuditLog>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__AuditLog__somename");
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.AuditDate).IsRequired();
entity.Property(e => e.UserName).HasMaxLength(256);
entity.Property(e => e.AuditAction).IsRequired().HasMaxLength(50);
entity.Property(e => e.EntityType).IsRequired().HasMaxLength(128);
entity.Property(e => e.EntityId).IsRequired().HasMaxLength(128);
entity.Property(e => e.OldValues).HasColumnType("nvarchar(max)");
entity.Property(e => e.NewValues).HasColumnType("nvarchar(max)");
entity.Property(e => e.ChangedColumns).HasColumnType("nvarchar(max)");
});
I have the following classes for my contexts:
public partial class DFDBContext : Audit.EntityFramework.AuditDbContext
public partial class DatabaseContext : DFDBContext
Example of my saving logic (not perfect structure, I know):
public static void UnlockLoad(string df)
{
using (var context = new DatabaseContext(AppConfig.ConnectionString))
{
LiveLoadLocking loadLock = context.LiveLoadLockings
.SingleOrDefault(x => x.somefield == somenumber);
loadLock.IsLocked = false;
loadLock.LockedBy = "";
loadLock.LastUpdated = DateTime.Now;
if (context.SaveChanges() <= 0) { throw new ContextFailedToSaveException("Items weren't saved or updated to the database.", loadLock); }
}
}
I can't seem to get around this identity error. Anyone have any tips? I have the same identity set up on many tables and have never hit this error before, so I assume that Audit is trying to insert the identity itself into the AuditLog table? Is there any workaround or way to stop it from trying to do that?
Thanks!
答案1
得分: 1
请注意,默认情况下,提供程序将从您的实体(LiveLoadLocking
)映射具有相同名称的属性到您的审计实体(AuditLog
)。
您可以禁用此机制,例如在流畅的配置 API 中调用 IgnoreMatchedProperties()
:
Audit.Core.Configuration.Setup()
.UseEntityFramework(cfg => cfg
.AuditTypeMapper(t =>
{
if (typesToAudit.Contains(t))
{
return typeof(AuditLog);
}
return null;
})
.AuditEntityAction((evt, entry, auditEntity) =>
{
AuditLog a = (AuditLog)auditEntity;
// ...
return true;
})
.IgnoreMatchedProperties()); // <-- 添加此行
通过这种方式,AuditLog
的属性将不会自动填充。
英文:
Take into consideration that, by default, the provider will map the properties with the same name from your entity (LiveLoadLocking
) to your audit entity (AuditLog
).
You can disable this mechanism, for example calling IgnoreMatchedProperties()
in the fluent configuration API:
Audit.Core.Configuration.Setup()
.UseEntityFramework(cfg => cfg
.AuditTypeMapper(t =>
{
if (typesToAudit.Contains(t))
{
return typeof(AuditLog);
}
return null;
})
.AuditEntityAction((evt, entry, auditEntity) =>
{
AuditLog a = (AuditLog)auditEntity;
// ...
return true;
})
.IgnoreMatchedProperties()); // <-- Add this
In this way, the AuditLog properties will not be auto-populated.
答案2
得分: 0
整数的数据类型在Audit.Net处理时默认为0,因此似乎尝试填充标识符!
解决方案:
public int? Id
在AuditLog类上!
英文:
Data Type of Int was defaulting to 0 when being handled by Audit.Net, hence it seeming like it's trying to fill in the identity!
Solution:
public int? Id
on AuditLog!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论