Ho una tabella che ha il Code
come PK, ma ottengo l'eccezione qui sotto in DefaultEditionCreator.cs una volta che provo a eseguire l'applicazione.
[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; }
}
Repository dichiarato:
private readonly IRepository<Article, string> _articleRepository;
Eccezione:
System.InvalidOperationException: 'Il campo specificato' k__BackingField 'di tipo' int 'non può essere utilizzato per la proprietà' Article.Id 'di tipo' string '. È possibile utilizzare solo i campi di backup dei tipi che sono assegnabili dal tipo di proprietà. '
Ricevo lo stesso errore durante l'esecuzione di Update-Database
e Add-Migration
.
@ Aaron Grazie mille per il vostro aiuto. Ho provato i passaggi come suggerito da te, ma sto ricevendo un errore durante l'aggiornamento e l'eliminazione dei record.
Eccezione:
ERRORE 2018-02-12 06: 13: 23,049 [30] Mvc.ExceptionHandling.AbpExceptionFilter - Si è verificato un errore durante l'aggiornamento delle voci. Vedi l'eccezione interna per i dettagli. Microsoft.EntityFrameworkCore.DbUpdateException: si è verificato un errore durante l'aggiornamento delle voci. Vedi l'eccezione interna per i dettagli. ---> System.Data.SqlClient.SqlException: impossibile aggiornare la colonna di identità "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; }
}
Sto cercando di disabilitare SoftDelete facendo riferimento a Disabilita SoftDelete per AbpUserRole , ma sta ancora eseguendo SoftDelete, non eliminando la riga dal DB. Si prega di trovare lo screenshot:
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);
}
}
La soluzione funziona bene, ma offre la seguente eccezione durante l'esecuzione del test case per creare l'entità Test
.
SQLite Error 19: 'NOT NULL constraint failed: Test.Id'.
L'eccezione è perché hai ereditato FullAuditedEntity<string>
, che specifica che Id
è di tipo string
, e poi ha fatto di new
per cambiare il tipo in int
. Questo nascondimento si traduce in un conflitto per EF.
Ecco come puoi:
Id
incremento automatico di tipo int
string
Codice:
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
}
}
Migrazione generata:
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);
}
Uso:
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;
}
Per completezza, questa domanda è la prima di una serie di altre domande di Stack Overflow:
Vuoi dire usare il tipo varchar come chiave primaria? Dichiara semplicemente la classe di entità come questa:
public class Article: Entity<string>
{
//You should comment this line
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
//new public int Id { get; set; }
}
Quindi puoi usare il repository:
private readonly IRepository<Article, string> _articleRepository;