[英]How update object with relation data in EntityFramework Core
I have used the Entity Framework Core
and update some object with relation to another object.我使用了Entity Framework Core
并更新了一些与另一个对象相关的对象。
I have a following entities:我有以下实体:
Client:客户:
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: 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);
}));
I would like update the ClientScope
for specific Client.Id
for example Id = 1.我想更新特定Client.Id
的ClientScope
,例如 Id = 1。
I have tried use this way:我试过用这种方式:
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);
But this way try to update the Client
as well.但是这种方式也尝试更新Client
。 I want to update only ClientScope and specify ClientId which it is stored on my form.我只想更新 ClientScope 并指定它存储在我的表单上的 ClientId。
What is the best way how update ClientScope
above?如何更新上面的ClientScope
的最佳方法是什么?
I have tried to implement the BaseRepository
which I want to implement for every entity something like this:我试图实现BaseRepository
,我想为每个实体实现这样的东西:
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;
}
}
But I don't know - How correctly specify the update
method for entities like this?但我不知道 - 如何正确地为这样的实体指定update
方法?
Thank you for any suggestion.谢谢你的任何建议。
If you never plan to add or modify a related entity via your repository methods you can simply set all other entities' state to EntityState.Unchanged
, eg:如果您从不打算通过存储库方法添加或修改相关实体,您可以简单地将所有其他实体的状态设置为EntityState.Unchanged
,例如:
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;
}
Alternatively, attach related entities as unchanged before calling the repo method(s).或者,在调用 repo 方法之前附加相关实体不变。 Perhaps create a repo method to return such an entity:也许创建一个 repo 方法来返回这样的实体:
public TEntity GetEntityPlaceholder( int id )
{
var entity = new TEntity() { Id = id };
_dbContext.Attach( entity );
return entity;
}
I prefer having the FK properties available, myself:我更喜欢 FK 属性可用,我自己:
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);
As mentioned in the comments (thanks, Ivan), EF needs to 'know about' the object you want to update.正如评论中提到的(谢谢,Ivan),EF 需要“了解”您要更新的对象。
Sorry, I don't have anything to hand to test this with, but your UpdateClientScope method should look something like this:抱歉,我没有任何可测试的东西,但您的 UpdateClientScope 方法应该如下所示:
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
}
}
I do not understand where is a problem ?我不明白是哪里出了问题? through DBContext object you can reach any class object than object's property, than just change a value of property with simple assign operator and just DbContext.SaveChanges() your changes will be updated in Database column with no problem at all.通过 DBContext 对象,您可以访问任何类对象而不是对象的属性,而不仅仅是使用简单的赋值运算符更改属性值,而只是 DbContext.SaveChanges() 您的更改将在数据库列中更新,完全没有问题。 If you want separate Update() method for changes you can do it with couple of code lines or more complex way with C# Reflection possibility but i can't imagine why would you need this ?!如果您想要单独的 Update() 方法进行更改,您可以使用几行代码或更复杂的方式来实现 C# 反射,但我无法想象您为什么需要这个?! If i missed something tell me more.如果我错过了什么,请告诉我更多。 Good luck !!!!祝你好运!!!!
i think your entities false because your ClientScope has not clientId (Foreign Key).我认为您的实体是错误的,因为您的 ClientScope 没有 clientId(外键)。
public string ClientId { get;公共字符串 ClientId { 获取; set;设置; } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.