如何在TabControl的DataGrid中显示EF Core外键关联数据?
使用Entity Framework Core + 数据库脚手架生成的实体,需要通过ID显示关联数据表的配料信息。简化后的Recipe实体类如下:
public partial class Recipe { public Recipe() { InterchangeabilityIngredients = new HashSet<InterchangeabilityIngredients>(); } public int Id { get; set; } public int IdBrand { get; set; } public int IdIngredient { get; set; } public double MassPart { get; set; } public double PercentWeight { get; set; } public virtual RubberBrand IdBrandNavigation { get; set; } public virtual Ingredient IdIngredientNavigation { get; set; } public virtual ICollection<InterchangeabilityIngredients> InterchangeabilityIngredients { get; set; } }
设置DataGrid的ItemsSource代码:
IngredientsBrandGrid.ItemsSource = db.Recipe.AsQueryable().Where(x => x.IdBrand == currentbrid).ToList();
DataGrid的XAML结构:
<DataGrid x:Name="IngredientsBrandGrid" SelectionMode="Single" IsReadOnly="True" HorizontalAlignment="Left" Margin="0,0,0,60" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="NameIngredient" Binding="{Binding IdIngredientNavigation.NameIngredient}" Width="200"> <DataGridTextColumn.ElementStyle> <Style> <Setter Property="TextBlock.TextWrapping" Value="Wrap" /> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn> <DataGridTextColumn Header="MassPart" Binding="{Binding MassPart}"/> <DataGridTextColumn Header="PercentWeight" Binding="{Binding PercentWeight}"/> </DataGrid.Columns> </DataGrid>
问题:NameIngredient列显示为空,尝试添加Include关联实体后仍无效:
IngredientsBrandGrid.ItemsSource = db.Recipe.Include(x=>x.IdIngredientNavigation).AsQueryable().Where(x => x.IdBrand == currentbrid).ToList();
注意:该DataGrid位于TabControl中,直接放在窗口中的DataGrid能正常显示数据。
1. 延迟绑定数据到Tab激活时
TabControl默认延迟加载未激活Tab的内容,可能导致绑定时机过早,关联属性未完成初始化。监听TabControl的SelectionChanged事件,在目标Tab选中时重新加载数据:
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) { var tabControl = sender as TabControl; if (tabControl?.SelectedItem is TabItem targetTab && targetTab.Name == "目标Tab的名称") { IngredientsBrandGrid.ItemsSource = db.Recipe .Include(x => x.IdIngredientNavigation) .Where(x => x.IdBrand == currentbrid) .ToList(); } }
2. 验证EF Core的关联配置
检查DbContext中的Fluent API配置,确认Recipe与Ingredient的外键关联正确:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Recipe>(entity => { entity.HasOne(d => d.IdIngredientNavigation) .WithMany(p => p.Recipes) // 对应Ingredient中的Recipe集合属性,无集合则用.WithOne() .HasForeignKey(d => d.IdIngredient) .OnDelete(DeleteBehavior.ClientSetNull); }); }
3. 调试确认关联实体加载状态
在数据绑定前添加调试断点,检查查询返回的Recipe对象中IdIngredientNavigation是否为null:
var recipes = db.Recipe .Include(x => x.IdIngredientNavigation) .Where(x => x.IdBrand == currentbrid) .ToList(); // 调试查看recipes中每个对象的IdIngredientNavigation是否有值 IngredientsBrandGrid.ItemsSource = recipes;
若为null,需检查数据库中IdIngredient对应的Ingredient记录是否存在,或外键配置是否错误。
4. 调整Include调用顺序
确保Include在Where之前调用(EF Core会自动优化,但规范写法可避免潜在问题):
IngredientsBrandGrid.ItemsSource = db.Recipe .Include(x => x.IdIngredientNavigation) .Where(x => x.IdBrand == currentbrid) .ToList();
5. 临时启用延迟加载排查
启用EF Core延迟加载,确认是否为加载问题(不建议长期使用,易引发N+1查询):
在DbContext构造函数中添加:
public YourDbContext(DbContextOptions<YourDbContext> options) : base(options) { ChangeTracker.LazyLoadingEnabled = true; }
实体中IdIngredientNavigation已为virtual属性,满足延迟加载条件。若启用后能显示,说明之前的Include未生效,需排查查询逻辑。
内容的提问来源于stack exchange,提问作者Miriskava

