Ho usato Entity Framework Core
e aggiornare alcuni oggetti in relazione a un altro oggetto.
Ho le seguenti entità:
Cliente:
public class Client
{
public int Id { get; set; }
public string ClientId { get; set; }
public string ClientName { get; set; }
public List<ClientScope> Scopes { get; set; }
}
ClientScope:
public class ClientScope
{
public int Id { get; set; }
public string Scope { get; set; }
public Client Client { get; set; }
}
OnModelCreating:
modelBuilder.Entity<Client>((Action<EntityTypeBuilder<Client>>) (client =>
{
client.ToTable<Client>(storeOptions.Client);
client.HasKey((Expression<Func<Client, object>>) (x => (object) x.Id));
client.Property<string>((Expression<Func<Client, string>>) (x => x.ClientId)).HasMaxLength(200).IsRequired(true);
client.HasIndex((Expression<Func<Client, object>>) (x => x.ClientId)).IsUnique(true);
client.HasMany<ClientScope>((Expression<Func<Client, IEnumerable<ClientScope>>>) (x => x.AllowedScopes)).WithOne((Expression<Func<ClientScope, Client>>) (x => x.Client)).IsRequired(true).OnDelete(DeleteBehavior.Cascade);
}));
modelBuilder.Entity<ClientScope>((Action<EntityTypeBuilder<ClientScope>>) (scope =>
{
scope.ToTable<ClientScope>(storeOptions.ClientScopes);
scope.Property<string>((Expression<Func<ClientScope, string>>) (x => x.Scope)).HasMaxLength(200).IsRequired(true);
}));
Vorrei aggiornare ClientScope
per Client.Id
specifico, ad esempio Id = 1.
Ho provato ad usare in questo modo:
public void UpdateClientScope(ClientScope scope){
_dbContext.ClientScope.Update(scope);
_dbContext.SaveChanges();
}
var scope = new ClientScope() { Client = new Client{Id = 1}, Id = 1, Scope = "Test Scope" }
UpdateClientScope(scope);
Ma in questo modo cerca di aggiornare anche il Client
. Voglio aggiornare solo ClientScope e specificare ClientId che è memorizzato nel mio modulo.
Qual è il modo migliore di aggiornare ClientScope
alto?
Ho cercato di implementare il BaseRepository
che voglio implementare per ogni entità qualcosa del genere:
public class BaseRepository<TDbContext, TEntity, TPrimaryKey> : IBaseRepository<TDbContext, TEntity, TPrimaryKey>
where TEntity : class
where TDbContext : DbContext
{
public virtual DbSet<TEntity> Table => _dbContext.Set<TEntity>();
private readonly TDbContext _dbContext;
public BaseRepository(TDbContext dbContext)
{
_dbContext = dbContext;
}
public virtual async Task<TEntity> UpdateAsync(TEntity entity)
{
Table.Update(entity);
await _dbContext.SaveChangesAsync();
return entity;
}
}
Ma non lo so - Come specificare correttamente il metodo di update
per entità come questa?
Grazie per qualsiasi suggerimento.
Se non si intende aggiungere o modificare un'entità correlata tramite i metodi del repository, è sufficiente impostare lo stato di tutte le altre entità su EntityState.Unchanged
, ad esempio:
public virtual async Task<TEntity> UpdateAsync(TEntity entity)
{
Table.Update(entity);
foreach( var entry in _dbContext.ChangeTracker.Entries() )
{
if( entry.Entity != entity )
{
entry.State = EntityState.Unchanged;
}
}
await _dbContext.SaveChangesAsync();
return entity;
}
In alternativa, allegare le entità correlate come immutate prima di chiamare i metodi repo. Forse creare un metodo repo per restituire una tale entità:
public TEntity GetEntityPlaceholder( int id )
{
var entity = new TEntity() { Id = id };
_dbContext.Attach( entity );
return entity;
}
Preferisco avere le proprietà FK disponibili, me stesso:
public class ClientScope
{
public int Id { get; set; }
public string Scope { get; set; }
public Client Client { get; set; }
// FK, use [ForeignKey( "Client" )] if you wish
public int ClientId { get; set; }
}
// or use FluentAPI
modelBuilder.Entity<ClientScope>()
.HasRequired( cs => cs.Client )
.WithMany( c => c.Scopes )
// specify foreign key
.HasForeignKey( cs => cs.ClientId );
// now can specify a client by setting the ClientId property
var scope = new ClientScope()
{
ClientId = 1,
Id = 1,
Scope = "Test Scope",
}
UpdateClientScope(scope);
Come menzionato nei commenti (grazie, Ivan), EF ha bisogno di "conoscere" l'oggetto che si desidera aggiornare.
Scusa, non ho nulla da mettere per testare questo, ma il tuo metodo UpdateClientScope dovrebbe assomigliare a questo:
public void UpdateClientScope(ClientScope scope){
// Get the existing object from the DB
ClientScope dbScope = _dbContext.ClientScope.FirstOrDefault(x => x.Id == scope.Id);
// Test it was in DB
if (dbScope != null)
{
// Update the database object
dbScope.Scope = scope.Scope;
dbScope.Client = scope.Client;
// SaveChanges works on dbScope
_dbContext.SaveChanges();
}
else
{
// Object not found, some error processing
}
}