我是.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足够聪明以至于忽略重复的事情?
答案 0 :(得分:0)
EF足够聪明,不会创建重复的表,最好将所有DbSet<>
包含在内。
当您有一个名称为Ingredient
的类并且在Recept
中增加了该类的名称时,将只有一个名称为Ingredient
的表,并且您不能有两个具有相同名称的表名称,因此即使您愿意也不会创建重复的表。
答案 1 :(得分:0)
您必须知道dbContext代表数据库。 DbSet代表数据库中的表
在实体框架中,表的列由类的非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多,...)
您的数据库将具有Recipes
和Ingredient
。每个Recipe
都会有零个或多个Ingredients
,而每个Ingredient
都会有零个或多个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
,因此实体框架可以检测到我设计了多对多的产品。实体框架甚至可以为我创建一个联结表,而不必声明它。
// 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中包含所有类?” : 您可以,这是完全好的方法。这样,您将确保所有类(要映射的类)都将被映射,而不必依赖于其他类引用它们。