[英]Loading navigation properties after an insert
我在插入后檢索導航屬性時遇到問題。
這是一個正確填充導航屬性的工作示例:
var entities = Context.MyEntities.Where(x => x.Id == myId).ToList();
//entities[0].MyNavProp is populated here...
問題是在插入之后....
var myEntity = new MyEntity
{
//all properties properly filled, no error in insert....
};
Context.MyEntity.Add(myEntity);
Context.SaveChanges();
//here, myEntity's navigation properties are null.... :(
這是我嘗試過的
Context.SaveChanges();
Context.Attach(myEntity);
Context.Entry(myEntity).Reload();
myEntity = Context.MyEntity.SingleOrDefault(x => x.Id == theId);
盡管如此,導航屬性仍然是 null。
我在Startup
設置中使用UseLazyLoadingProxies
。
如果我在單獨的請求中對數據庫進行簡單查詢,就像這樣
var result = Context.MyEntity.SingleOrDefault(x => x.Id == 31);
我得到了Castle.Proxies.MyEntityProxy
類型的實體,但是在插入后立即執行相同的查詢時,我得到了MyEntity
類型的實體。
看起來代理延遲加載功能在這種情況下不起作用。
好吧,現在的解決方案是創建一個顯式代理。
代替
var myEntity = new MyEntity
{
//all properties properly filled, no error in insert....
};
經過
var myEntity = Context.MyEntity.CreateProxy();
//populate entities, add to context and SaveChanges()....
您的導航屬性將被正確填充,至少在我的情況下是這樣。
UseLazyLoadingProxies
要求所有實體類型都是公共的、未密封的、具有虛擬導航屬性並具有公共或受保護的構造函數。
另一個需要注意的重點是在使用UseLazyLoadingProxies
從上下文中恢復實體時不要使用AsNoTracking()
。
我復制了類似的風景,它對我來說是正確的。
實施細節:
Thing
實體(類似於子聚合):
public class Thing : Entity<Guid>
{
internal Thing(Guid id, string name, string type, double value)
{
SetId(id);
SetName(name);
SetType(type);
SetValue(value);
}
// The default constructor must be explicitly defined,
// for use Lazy Loading Proxies.
protected Thing() { }
public string Name { get; private set; }
public string Type { get; private set; }
public double Value { get; private set; }
// Setters commented for brevity
}
Whatever
實體(根聚合):
public class Whatever : Entity<Guid>
{
internal Whatever(Guid id, string name, DateTime time, string type)
{
SetId(id);
SetName(name);
SetTime(time);
SetType(type);
Things = new List<Thing>();
}
// The default constructor must be explicitly defined,
// for use Lazy Loading Proxies.
protected Whatever() { }
public string Name { get; private set; }
//Virtual navigation required
public virtual ICollection<Thing> Things { get; }
public DateTime Time { get; private set; }
public string Type { get; private set; }
// Setters commented for brevity
}
實體類型配置:
public class WhateverConfig : IEntityTypeConfiguration<Whatever>
{
public void Configure(EntityTypeBuilder<Whatever> builder)
{
// commented for brevity
builder.HasMany(x => x.Things);
}
}
國際奧委會:
public static IServiceCollection AddDbContext(this IServiceCollection services, Action<RepositoriesOptions> options)
{
options.Invoke(RepositoriesOptions);
return services.AddDbContext<WhateverContext>(dbContextOptions
=> dbContextOptions.UseLazyLoadingProxies()
.UseSqlite(RepositoriesOptions.ConnectionString, sqliteOptions
=> sqliteOptions.MigrationsAssembly(typeof(WhateverContext).Assembly.GetName().Name)));
}
存儲庫:
public virtual async Task InsertAsync(TEntity entity, CancellationToken cancellationToken)
{
if (await ExistsAsync(entity.Id, cancellationToken).ConfigureAwait(false)) return;
await _dbSet.AddAsync(entity, cancellationToken);
await _context.SaveChangesAsync(true, cancellationToken);
}
服務:
public async Task<TEntity> SaveAsync(TModel model, CancellationToken cancellationToken)
{
var entity = _mapper.Map<TEntity>(model);
if (entity.IsValid) await _repository.InsertAsync(entity, cancellationToken);
return entity;
}
保存后從服務返回的entity
:
使用的版本:
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="3.1.3" />
</ItemGroup>
我希望它能以某種方式幫助你。
我找到了可行的解決方案
調用SaveChanges()
后執行以下代碼:
IList<EntityEntry> entries = _context.ChangeTracker.Entries().ToList();
foreach (EntityEntry e in entries)
{
e.State = Microsoft.EntityFrameworkCore.EntityState.Detached;
}
設置狀態后,我們必須通過First(item => item.Id == id)/FirstOrDefault()
或使用其他方法從 DbSet 讀取我們的頂級 Model 項目
在哪里:
我的 Ef Core 版本是:
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.