为了账号安全,请及时绑定邮箱和手机立即绑定

使用 EF 将 T 从 DbSet<T> 映射到数据库内部表示

使用 EF 将 T 从 DbSet<T> 映射到数据库内部表示

C#
慕侠2389804 2022-11-22 15:48:20
我是 .NET 和 Entity Framework 的初学者,只是一个关于映射的问题,假设我们有 Recipes 类,其属性是 Ingredient,所以我们有两个类 Recipes 和 Ingredient。我们通过以下方式进行映射:public DbSet<Recipe> Recipes { get; set; }因此 EF 将检查 Recipe 的属性并创建一个 Recipes 表,最终它将找到 Ingredient 作为属性,因此它将创建一个 Ingredient 表。到目前为止它似乎很简单,但这是一个非常简单的结构,所以我们知道 Recipes 包含 Ingredient,所以我们不这样做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 中包含所有类吗?如果我们这样做,将会有重复的声明,但如果我们不这样做,我们可能会丢失映射。所以我想我们只是为所有类做 tat 并期望 EF 足够聪明以忽略重复的东西?
查看完整描述

3 回答

?
慕姐4208626

TA贡献1852条经验 获得超7个赞

EF 足够聪明,不会创建重复的表,最好将DbSet<>.

当你有一个带有名称的类Ingredient并且你在其中引用它时Recept,将只有一个带有名称Ingredient的表并且你不能有两个具有相同名称的表所以即使你想要也不会创建重复的表。


查看完整回答
反对 回复 2022-11-22
?
HUX布斯

TA贡献1876条经验 获得超6个赞

正如您已经说过的,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 中包含所有类吗?” : 你可以,这是完全好的方法。这样您将确保所有类(您想要映射)都将被映射,而不必依赖于它们被其他类引用。


查看完整回答
反对 回复 2022-11-22
?
红颜莎娜

TA贡献1842条经验 获得超12个赞

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


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


您的数据库将有Recipes和Ingredient。EveryRecipe将有零个或多个Ingredients,而 everyIngredient用于零个或多个Recipes:一个简单的多对多关系。


您将拥有表Recipes和Ingredients,因此您的 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两边都用了,Recipes和Ingredients,entity framework可以检测到我设计的是多对多。实体框架甚至会为我创建一个联结表,我不必声明它。


// 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(),

    });

类似的:给我所有学生和他们就读的学校


查看完整回答
反对 回复 2022-11-22
  • 3 回答
  • 0 关注
  • 94 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信