使用EF将DbSet <t>中的T映射到Dabase内部表示中

时间:2019-04-03 06:10:52

标签: c# asp.net entity-framework entity-framework-core

我是.NET和Entity Framework的初学者,仅是有关映射的问题,可以说我们有属性为Ingredient的Recipes类,因此我们有Recipes和Ingredient两个类。

我们通过以下方式进行映射:

public DbSet<Recipe> Recipes { get; set; }

因此EF将检查配方的属性并创建配方表,最终它将找到成分作为属性,因此它将创建成分表。 到目前为止,这似乎很简单,但这是一个非常简单的结构,因此我们知道食谱包含成分,所以我们不喜欢

public DbSet<Recipe> Recipes { get; set; }
public DbSet<Ingredient> Ingredient { get; set; } //duplicated 

但是可以想象,在一个复杂的应用程序中,我们可能有数百个类,所以当我们这样做时

public DbSet<T> T{ get; set; }
public DbSet<U> U{ get; set; }
public DbSet<V> V{ get; set; }
...

T可能包含U作为属性,而U可能包含V作为属性, 所以我们只需要像这样的代码:

public DbSet<T> T{ get; set; }

所以我很困惑,我们应该在DbContext中包含所有类吗?如果这样做,将有重复的声明,但是如果不这样做,则可能会丢失映射。 所以我想我们只是对所有课程都做了些练习,并期望EF足够聪明以至于忽略重复的事情?

3 个答案:

答案 0 :(得分:0)

EF足够聪明,不会创建重复的表,最好将所有DbSet<>包含在内。

当您有一个名称为Ingredient的类并且在Recept中增加了该类的名称时,将只有一个名称为Ingredient的表,并且您不能有两个具有相同名称的表名称,因此即使您愿意也不会创建重复的表。

答案 1 :(得分:0)

您必须知道dbContext代表数据库。 DbSet代表数据库中的表

  

在实体框架中,表的列由类的非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多,...)

您的数据库将具有RecipesIngredient。每个Recipe都会有零个或多个Ingredients,而每个Ingredient都会有零个或多个Recipes:直接的多对多关系。

您将拥有表RecipesIngredients,因此您的dbContext将具有DbSets

class MyDbContext : DbContext
{
    public DbSet<Recipe> Recipes {get; set;}
    public DbSet<Ingredient> Ingredients {get; set;}
}

class Recipe
{
    public int Id {get; set;}  // primary key
    ...                        // other columns

    // every Recipe has zero or more ingredients (many-to-many)
    public virtual ICollection<Ingredient> Ingredients {get; set;}
}

class Ingredient
{
    public int Id {get; set;}  // primary key
    ...                        // other columns

    // every Ingredient is used in zero or more Recipes( many-to-many)
    public virtual ICollection<Recipe> Recipes {get; set;}
}

由于我在食谱和配料两面都使用了virtual,因此实体框架可以检测到我设计了多对多的产品。实体框架甚至可以为我创建一个联结表,而不必声明它。

// Fetch all Desserts with their Bitter ingredients
var desertsWithoutSugar = myDbContext.Recipes
    .Where(recipe => recipy.Type == RecipyType.Dessert)
    .Select(recipe => new
    {
        // select only the properties that I plan to use:
        Id = recipe.Id,
        Name = recipe.Name,
        ...
        // not needed: you know the value: Type = recipe.Type

        Ingredients = recipe.Ingredients
           .Where(ingredient => ingredient.Taste == Taste.Bitter)
           .Select(ingredient => new
           {
               // again: only the properties you plan to use
               Id = ingredient.Id,
               Name = ingredient.Name,
           })
           .ToList(),
     })

实体框架了解您的多对多关系,并且足够聪明,可以检测到需要三个表(包括结点表)的(组)联接。

如果您要设计一对多关系,例如一所学校和他的学生,则只在一侧声明virtual ICollection。另一端获取外键。这是表中的一列,因此是非虚拟的

class School
{
    public int Id {get; set;}
    ...                     

    // every School has zero or more Students (one-to-many)
    public virtual ICollection<Student> Students {get; set;}
}
class Student
{
    public int Id {get; set;}
    ...   

    // Every Student studies at one School, using foreign key
    public int SchoolId {get; set;}
    public virtual School School {get; set;}
}
public SchoolContext : DbContext
{
    public DbSet<School> Schools {get; set;}
    public DbSet<Student> Students {get; set;}
}

根据我的经验,由于我使用实体框架,因此我几乎不必再进行(Group-)join,因此我使用集合:

  

把所有学校和他们的学生给我

var Result = dbContext.Schools
    .Where(school => ...)
    .Select(school => new
    {
        Id = school.Id,
        ...

        Students = school.Students
            .Where(student => ...)
            .Select(student => new
            {
                 Id = student.Id,
                 ...
            })
            .ToList(),
    });

和类似的:给我所有学生一起就读的学校

答案 2 :(得分:0)

正如您已经说过的,EF将在Ingredient属性中找到Recipe类型并创建Ingredients表。这意味着Ingredients表将被创建,即使您省略了public DbSet<Ingredient> Ingredient { get; set; }。但是,仅仅因为您不需要public DbSet<Ingredient> Ingredient { get; set; },并不意味着您不必拥有它。您可以随意包含它,它不会造成任何伤害,也不会创建任何重复项。

在您的public DbSet<Ingredient> Ingredient { get; set; }中添加DbContext可使您直接从上下文访问Ingredient条目:

MyContext context = ...
var ingredients = context.Ingredients;

否则,您将必须通过Ingredient属性访问Recipes条目:

MyContext context = ...
var recipe = context.Recipes...;
var ingredients = recipe.Ingredients;

摘要:什么时候应该在DbContext中包含该类?

  • DbContext中的任何其他类未引用该类时。将类添加到DbContext将确保它已被映射。

  • 当您希望能够直接从DbContext实例访问该类的条目时。例如。 var ingredients = context.Ingredients

  • 当您要确保该类将被映射,并且不想依赖于其他映射类引用它时。

因此,要回答您的问题“我们是否应在DbContext中包含所有类?” : 您可以,这是完全好的方法。这样,您将确保所有类(要映射的类)都将被映射,而不必依赖于其他类引用它们。