为什么一对多关系给我null(实体框架)?

时间:2019-06-13 13:00:20

标签: entity-framework .net-core

我具有以下应用程序数据库上下文:

public class ApplicationContext : DbContext
{
    private readonly string _connectionString;

    public ApplicationContext(IConfiguration configuration)
    {
        _connectionString = configuration.GetConnectionString("Recipes");
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Recipe> Recipes { get; set; }
    public DbSet<Ingredient> Ingridients { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseNpgsql(_connectionString);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Ingredient>()
            .HasOne(x => x.Recipe)
            .WithMany(y => y.Ingredients);
    }
}

我的商业模式很简单:一种食谱有很多成分,而一种成分只有一张收据。

模型

食谱:

public class Recipe
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public List<Ingredient> Ingredients { get; set; }

    public DateTime CreatedAt { get; set; }

    public DateTime UpdatedAt { get; set; }

    public Recipe()
    {
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }
}

成分

public class Ingredient
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int ClientId { get; set; }

    public string Name { get; set; }

    public decimal Count { get; set; }

    public string Measure { get; set; }

    public int Number { get; set; }  

    public DateTime CreatedAt { get; set; }

    public DateTime UpdatedAt { get; set; }

    public Recipe Recipe { get; set; }

    public Ingredient()
    {
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }
}

在这里,我正在尝试从食谱中收集食材:

List<Recipe> recipes;


recipes = _applicationContext.Recipes.Where(r => r.Category.ClientId == id).ToList();

但是成分始终为空。我不明白为什么。结果如下:

enter image description here

怎么了?

3 个答案:

答案 0 :(得分:2)

您需要在查询中包括子属性,否则将从它们返回null。这样做是为了保持Entity Framework的快速性能。如果自动包含所有子属性,则在EF生成的sql查询中可能会生成许多不必要的联接,这可能会对性能造成很大的影响(如果是这种情况,我们可能会使用.Exclude扩展方法! )

即:

List<Recipe> recipes = _applicationContext.Recipes.Include(x => x.Ingredients).Where(r => r.Category.ClientId == id).ToList();

答案 1 :(得分:1)

除了@GregH所说的以外,您可以将Ingredients标记为virtual,以便可以将它们延迟加载。

public class Recipe
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual List<Ingredient> Ingredients { get; set; } // marked as virtual

    public DateTime CreatedAt { get; set; }

    public DateTime UpdatedAt { get; set; }

    public Recipe()
    {
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }
}

现在,您可以按照接受的答案中的说明急于加载它们,也可以像以前尝试过的那样延迟加载它们。

答案 2 :(得分:1)

如果要将导航属性延迟加载,我认为您需要将它们设置为虚拟。

public virtual ICollection<Ingredient> Ingredients { get; set; }

或者您可以将它们包括在查询中,以便与收件人同时获取它们。

recipesWithIngredients = _applicationContext.Recipes
    .Include(r => r.Ingredients)
    .Where(r => r.Category.ClientId == id)
    .ToList();