Я пытаюсь настроить отношения «многие ко многим» между двумя таблицами, Employee
и Project
.
Один Employee
может участвовать во многих проектах, а над одним проектом может работать много Employees
. Поэтому я создал два класса моделей Employee
и Project
и добавил таблицу Employee_Project
.
Это три моих модельных класса:
namespace WebApp2.Models
{
public class Employee
{
[Key]
public int Emp_Id { get; set; }
public string Emp_Name { get; set; }
public string Emp_Email { get; set; }
public string Emp_Mobile { get; set; }
public virtual ICollection<Employee_Project> Employee_Projects { get; set; }
}
public class Project
{
[Key]
public int Proj_Id { get; set; }
public string Proj_Name { get; set; }
public string Project_Details { get; set; }
public virtual ICollection<Employee_Project> Employee_Projects { get; set; }
}
public class Employee_Project
{
[Key]
[Column(Order =1)]
public int Emp_Id { get; set; }
[Key]
[Column(Order = 2)]
public int Proj_Id { get; set; }
public virtual Employee Employee { get; set; }
public virtual Project Project { get; set; }
}
}
Затем я добавил этот класс DbContext
:
namespace WebApp2.Data
{
public class MyDbContext:DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> option):base(option)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Project> Projects { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee_Project>().HasKey(pt => new { pt.Proj_Id, pt.Emp_Id });
modelBuilder.Entity<Employee_Project>()
.HasOne(pt => pt.Employee)
.WithMany(pt => pt.Employee_Projects)
.HasForeignKey(p => p.Emp_Id);
modelBuilder.Entity<Employee_Project>()
.HasOne(pt => pt.Project)
.WithMany(pt => pt.Employee_Projects)
.HasForeignKey(p => p.Proj_Id);
}
public DbSet<Employee_Project> Employee_Projects { get; set; }
}
}
Я создал после этого три контроллера
public class ProjectController : Controller
{
private readonly MyDbContext _context;
public ProjectController(MyDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View(_context.projects.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(Project project)
{
_context.projects.Add(project);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
public class EmployeeController : Controller
{
private readonly MyDbContext _context;
public EmployeeController(MyDbContext context)
{
_context = context;
}
public IActionResult Index()
{
return View(_context.Employees.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(Employee employee)
{
_context.Employees.Add(employee);
_context.SaveChanges();
return RedirectToAction("Index");
}
}
public class Emp_ProjController : Controller
{
private readonly MyDbContext _DbContext;
public Emp_ProjController(MyDbContext DbContext)
{
_DbContext = DbContext;
}
public IActionResult Index()
{
return View(_DbContext.Employee_Projects.ToList());
}
public IActionResult Create()
{
ViewBag.emp=_DbContext.Employees.ToList();
ViewBag.pro=_DbContext.projects.ToList();
return View();
}
[HttpPost]
public IActionResult Create(int empid, int [] projIds)
{
foreach (var item in projIds)
{
Employee_Project emp = new Employee_Project();
emp.Emp_Id = empid;
emp.Proj_Id = item;
_DbContext.Employee_Projects.Add(emp);
_DbContext.SaveChanges();
}
return RedirectToAction("Index");
}
}
После этого foreach Controllers я сделал представление для метода Index и Create
Эмп_Продж
// просмотр индекса
@model IEnumerable<WebApp2.Models.Employee_Project>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action = "Create">Create New</a>
</p>
<table class = "table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Employee.Emp_Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Project.Proj_Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Employee.Emp_Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Project.Proj_Name)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>
//view Create
<h2>Create</h2>
<form method = "post">
<div>
<label>Employee Name</label>
@Html.DropDownList("empid", new SelectList(ViewBag.emp, "Emp_Id","Emp_Email"),"Select Employee")
</div>
<div>
<label>Select Project</label>
@* @Html.DropDownList("proid", new SelectList(ViewBag.pro, "Proj_Id","Proj_Name"),"Select Project")*@
<ul>
@foreach(var item in ViewBag.pro )
{
<li>
<input type = "checkbox" name = "projIds" value = "@item.Proj_Id">@item.Proj_Name
</li>
}
</ul>
<input type = "submit" value = "SaveData"/>
</div>
</form>
У меня нет проблем с сотрудником и проектом, я обнаружил проблему, когда хочу создать элемент Emp_Proj. введите здесь описание изображения Мне всегда выдает такую ошибку:
SqlException: нарушение ограничения PRIMARY KEY «PK_Employee_Projects». Не удается вставить повторяющийся ключ в объект «dbo.Employee_Projects». Повторяющееся значение ключа: (1, 1). Инструкция прекращена.
введите здесь описание изображения
Может кто-нибудь, пожалуйста, помогите мне найти проблему? Заранее спасибо.
Я пытаюсь найти проблему, и я ценю некоторую помощь.
Возможно, проверьте порядок ключей в modelBuilder.Entity<Employee_Project>().HasKey(pt => new { pt.Proj_Id, pt.Emp_Id });
@ValNik, я не понимаю порядок ключей
В Employee_Project: определенный порядок столбцов Emp_id = 1, порядок столбцов Proj_Id = 2. И затем вы используете новый {Proj_id, Emp_id}
Сообщение об ошибке показывает причину возникновения этого исключения: база данных уже содержит эту запись, вы не можете вставлять повторяющиеся данные. Вам просто нужно проверить, существует ли он уже в базе данных, прежде чем вставлять данные. Пожалуйста, обратитесь к этой простой демонстрации.
[HttpPost]
public IActionResult Create(int empid, int[] projIds)
{
foreach (var item in projIds)
{
//check if the database already has this record
var empdb = _DbContext.Employee_Projects.Where(x => x.Emp_Id == empid && x.Proj_Id == item).FirstOrDefault();
if (empdb==null)
{
Employee_Project emp = new Employee_Project();
emp.Emp_Id = empid;
emp.Proj_Id = item;
_DbContext.Employee_Projects.Add(emp);
}
}
_DbContext.SaveChanges();
return RedirectToAction("Index");
}
Привет, Xinran Shen Большое спасибо, все работает правильно, я вижу все свои записи в базе данных, но не вижу данных в таблице, таблица пуста. На странице индекса Emp_ProjController я хочу увидеть имя сотрудника и название проекта, но оно пустое.
@ user95 что вы подразумеваете под «записями»? вы пытаетесь засеять данные? как вы пытаетесь вставить данные? ваша проблема с пустой таблицей? или имена сотрудников и проектов не представлены в качестве столбцов для таблицы ассоциаций? потому что это совсем другая тема.
вам, вероятно, следует задать новый вопрос, так как ваша проблема исчезла.
когда я добавил некоторых сотрудников и проекты, он работает, но я не вижу данные в индексе представления, но когда я открыл свою таблицу Employee_Projects на сервере sql, я вижу все записи. Могу ли я отправить другие изображения?
Во-первых, попробуйте полностью удалить объект «Employee_Project» и посмотрите, сможет ли EF Core создать его автоматически. EF Core должен иметь возможность автоматически создавать ассоциативную таблицу, если для двух сущностей заданы два навигационных свойства. Обратите внимание, что навигационные свойства двух объектов должны ссылаться друг на друга. вот так;
в Сотрудник;
public virtual ICollection<Project> Projects { get; set; }
и в проекте;
public virtual ICollection<Employee> Employees { get; set; }
Если это не сработает, измените свой класс Employee_Project следующим образом;
public class Employee_Project
{
[Key]
[Column(Order =1)]
public int EmployeeId { get; set; }
[Key]
[Column(Order = 2)]
public int ProjectId { get; set; }
public virtual Employee Employee { get; set; }
public virtual Project Project { get; set; }
}
Возможно, проблема заключалась в именовании столбцов.
Исключение объясняет само себя, не так ли? Вы не проверяете, существует ли комбинация уже в базе данных.