我有一个表有Code
作为PK,但是一旦我尝试运行应用程序,我在DefaultEditionCreator.cs中得到了例外。
[Table("Test")]
public class Test: FullAuditedEntity<string>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
new public int Id { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[MaxLength(NVarcharLength14), DataType(DataType.Text)]
public virtual string Code { get; set; }
}
声明的存储库:
private readonly IRepository<Article, string> _articleRepository;
例外:
System.InvalidOperationException:''int'类型的指定字段'k__BackingField'不能用于'string'类型的属性'Article.Id'。只能使用可从属性类型分配的类型的备份字段。
我在运行Update-Database
和Add-Migration
时遇到了同样的错误。
@aaron非常感谢你的帮助。我已尝试过您建议的步骤,但在更新和删除记录时遇到错误。
例外:
ERROR 2018-02-12 06:13:23,049 [30] Mvc.ExceptionHandling.AbpExceptionFilter - 更新条目时发生错误。有关详细信息,请参阅内部异常Microsoft.EntityFrameworkCore.DbUpdateException:更新条目时发生错误。有关详细信息,请参阅内部异常---> System.Data.SqlClient.SqlException:无法更新标识列'Id'。
public async Task UpdateTest()
{
var entity = GetAll().Where(x => x.TestId == "One").FirstOrDefault();
await UpdateAsync(entity);
}
public async Task DeleteTest()
{
await DeleteAsync(x => x.TestId == "One");
}
public class Test : FullAuditedEntity
{
// PK
public string TestId { get; set; }
// Unique constraint
public int TestId2 { get; set; }
}
我试图通过引用Disable SoftDelete for AbpUserRole来禁用SoftDelete,但它仍在使用SoftDelete,而不是从DB中删除行。请找截图:
public class TestAppService : MyProjectAppServiceBase, ITestAppService
{
public Task DeleteTest()
{
using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.SoftDelete))
{
return _testRepository.DeleteTest();
}
}
}
MyDBContext.cs:
protected override void CancelDeletionForSoftDelete(EntityEntry entry)
{
if (IsSoftDeleteFilterEnabled)
{
base.CancelDeletionForSoftDelete(entry);
}
}
解决方案工作正常,但它在运行测试用例创建Test
实体时给出以下异常。
SQLite错误19:'NOT NULL约束失败:Test.Id'。
唯一的例外是因为你继承了FullAuditedEntity<string>
,它指定Id
是string
类型,然后new
将类型更改为int
。这个hiding导致EF的冲突。
以下是您的方法:
Id
类型的自动增量int
列string
类型的主键列码:
public class Test: FullAuditedEntity
{
// PK
[MaxLength(NVarcharLength14), DataType(DataType.Text)]
public virtual string Code { get; set; }
// Unique constraint
public int MyUniqueId { get; set; }
}
public class AbpProjectNameDbContext : AbpZeroDbContext<Tenant, Role, User, AbpProjectNameDbContext>
{
/* Define a DbSet for each entity of the application */
public DbSet<Test> Tests { get; set; }
public AbpProjectNameDbContext(DbContextOptions<AbpProjectNameDbContext> options) : base(options) {}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Test>().Property(t => t.Id).ValueGeneratedOnAdd(); // Auto-increment
modelBuilder.Entity<Test>().HasAlternateKey(t => t.Id); // Auto-increment, closed-wont-fix: https://github.com/aspnet/EntityFrameworkCore/issues/7380
modelBuilder.Entity<Test>().HasKey(t => t.Code); // PK
modelBuilder.Entity<Test>().HasIndex(t => t.MyUniqueId).IsUnique(); // Unique constraint
}
}
生成的迁移:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Tests",
columns: table => new
{
Code = table.Column<string>(nullable: false),
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
MyUniqueId = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tests", x => x.Code);
});
migrationBuilder.CreateIndex(
name: "IX_Tests_MyUniqueId",
table: "Tests",
column: "MyUniqueId",
unique: true);
}
用法:
public async Task MyMethod()
{
await _repository.InsertAndGetIdAsync(new Test
{
Code = "One",
MyUniqueId = 1
});
// Valid
await _repository.InsertAndGetIdAsync(new Test
{
Code = "Two",
MyUniqueId = 2
});
try
{
await _repository.InsertAndGetIdAsync(new Test
{
Code = "One", // PK conflict
MyUniqueId = 3
});
}
catch (Exception e)
{
}
try
{
await _repository.InsertAndGetIdAsync(new Test
{
Code = "Three",
MyUniqueId = 1 // Unique constraint conflict
});
}
catch (Exception e)
{
throw;
}
return null;
}
为了完整起见,这个问题是一系列其他Stack Overflow问题中的第一个:
你的意思是使用varchar类型作为主键吗?只需像这样声明实体类:
public class Article: Entity<string>
{
//You should comment this line
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
//new public int Id { get; set; }
}
然后你可以使用存储库:
private readonly IRepository<Article, string> _articleRepository;