C# 实体框架在模型C中不映射多个列表#
我有一个类“Project”,它有两个列表,一个是“Employee”,另一个是“tool”,当我只使用其中一个列表构建项目时,数据库会以正确的关系更新,如果将第二个列表添加到类实体框架中,则无法了解如何创建关系C# 实体框架在模型C中不映射多个列表#,c#,asp.net-mvc,entity-framework,ef-fluent-api,C#,Asp.net Mvc,Entity Framework,Ef Fluent Api,我有一个类“Project”,它有两个列表,一个是“Employee”,另一个是“tool”,当我只使用其中一个列表构建项目时,数据库会以正确的关系更新,如果将第二个列表添加到类实体框架中,则无法了解如何创建关系 public class Project { public Guid Id { get; set; } public List<Employee> RequiredEmployees {get;set;} public List&l
public class Project
{
public Guid Id { get; set; }
public List<Employee> RequiredEmployees {get;set;}
public List<Tools> RequiredTools {get;set;}
}
Public class Tool
{
public Guid Id { get; set; }
public string Name { get; set; }
public Project Project { get; set; }
public Guid ProjectId { get; set; }
}
公共类项目
{
公共Guid Id{get;set;}
公共列表RequiredEmployees{get;set;}
公共列表所需工具{get;set;}
}
公共类工具
{
公共Guid Id{get;set;}
公共字符串名称{get;set;}
公共项目{get;set;}
公共Guid项目ID{get;set;}
}
我得到错误“引用的表中没有主键或候选键”
我曾尝试在ModelBuilder中映射,但没有成功
modelBuilder.Entity<Employee>()
.HasRequired<Project>(s => s.Project)
.WithMany(g => g.Employee)
.HasForeignKey<Guid>(s => s.ProjectId);
modelBuilder.Entity()
.HasRequired(s=>s.Project)
.WithMany(g=>g.Employee)
.HasForeignKey(s=>s.projectd);
有什么想法吗?当然,我们需要查看您的
工具
类,但我认为问题在于实体框架找不到用作主键的属性
实体框架约定将类的主键命名为
Id
或Id
(在本例中为ToolsId
)。如果您希望一个名称与此名称不同的属性作为PK,则必须使用或显式地指定它。您已经在几个问题上进行了调整。报告的错误与主键有关。此外,您在指定一对多关系时遇到问题
一对多关系
实体框架是很容易的,如果您遵循的每一个偏差,您需要告诉实体框架有关您的偏差
您计划在项目
和工具
之间设计一对多:每个项目
都有零个或多个工具
,每个工具
只属于一个项目
如果您遵循的是惯例,则不必将此关系告知实体框架;实体框架将按约定检测关系:
- 使用ICollection而不是列表,毕竟,
意味着什么RequiredTools[4]
- 使ICollection虚拟化。只要您的项目是一个查询,它就不是一个真正的ICollection,它只包含一个可以生成ICollection的类
class Project
{
public Guid Id { get; set; }
// a project has zero or more Employees:
public virtual ICollection<Employee> Employees {get;set;}
// a project has zero or more Tools
public virtual ICollectioin<Tool> Tools {get;set;}
}
类似地:每个员工都属于一个项目
class Employee
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid ProjectId {get; set;}
public virtual Project Project { get; set; }
}
或者,如果员工可以参与多个项目,则使用:
class Employee
{
public Guid Id { get; set; }
public string Name { get; set; }
// an Employee works in zero or more Projects
public virtual ICollection<Project> Projects { get; set; }
}
如果忘记实现Id,编译器将警告您。GenerateID现在相当简单:
private void GenerateIds()
{
foreach (DbEntityEntry addedEntry in this.ChangeTracker.Entries()
.Where(entry => entry.State == EntityState.Added))
{
// every entry implements IPrimaryKey. Fill the Id
(IPrimaryKey)entry.Id = this.CreateId
}
}
private GUID CreateId()
{
return Guid.NewGuid(); // or use your own Guid creator
}
您可以在主键字段中添加
KeyAttribute
:[key]public Guid Id{get;set;}
,然后运行Update Database
。发布Tools
类。EF在那里找不到钥匙。如果可能的话,将其重命名为Tool
。此外,它将是。对于许多(g=>g.RequiredEmployees)
我已经添加了简化的“Tool”类,并且我已经在id上添加了[Key],它仍然不起作用。“不起作用”从来都不是很清楚或者很有用。发布准确的错误消息和所涉及的准确行。我已经添加了[Key]public Guid Id{get;set;},但这并不能很好地回答这个问题!“您选择不使用常规类型作为主键”是什么意思?您的意思是OP使用了Guid
而不是int
?我们不能用[DatabaseGenerated(DatabaseGeneratedOption.Identity)]完成同样的PK装饰吗?不,我不是这个意思。我的意思是,一个人没有Id
或PersonId
作为主键,而一个订单没有Id
或OrderId
作为主键。如果您使用这些标识符中的一个,实体框架将假定这是主键。如果您选择使用不同的标识符,则t.o将告诉实体框架主键的名称
class MyDbContext : DbContext
{
public DbSet<Employee> Employees {get; set;}
public DbSet<Project> Projects {get; set;}
public DbSet<Tool> Tools {get; set;}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// a Project has zero or more Tools via property RequiredTools and table TableName:
var entityProject = modelBuilder.Entity<Project>();
entityProject.ToTable(... /* table name */);
// a project has zero or more tools via property RequiredTools
// every tool belongs to one required Project
// using foreign key ProjectId
entityproject.HasMany(project => project.RequiredTools)
.WithRequired(tool => tool.Project)
.HasFreignKey(tool => tool.ProjectId);
}
public override int SaveChanges()
{
GenerateIds();
return base.SaveChanges();
}
public override Task<int> SaveChangesAsync()
{
GenerateIds();
return base.SaveChangesAsync();
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
this.GenerateIds();
return base.SaveChangesAsync(cancellationToken);
}
public interface IPrimaryKey
{
GUID Id {get; set;}
}
class Tool : IPrimaryKey {...}
class Project : IPrimaryKey {...}
private void GenerateIds()
{
foreach (DbEntityEntry addedEntry in this.ChangeTracker.Entries()
.Where(entry => entry.State == EntityState.Added))
{
// every entry implements IPrimaryKey. Fill the Id
(IPrimaryKey)entry.Id = this.CreateId
}
}
private GUID CreateId()
{
return Guid.NewGuid(); // or use your own Guid creator
}