#c# #asp.net-mvc #entity-framework
#c# #asp.net-mvc #entity-framework
Вопрос:
Я все еще изучаю entity framework с помощью MVC и пытаюсь создать универсальный торговый сайт. У меня есть модели — категория и продукты, имеющие отношение «один ко многим» (например: продукт «iPhone7» будет принадлежать категории «Электроника») Смотрите Диаграмму edmx моделей здесь
Проблема в том, что всякий раз, когда я добавляю новый продукт, скажем, P, принадлежащий категории C, EF автоматически добавляет новую запись C в таблицу категорий, даже если C уже существует в таблице категорий. Я считаю, что проблема заключается в том, как EF обрабатывает отношения «один ко многим». Я также попытался добавить [Index(isUnique = true)] в CategoryName в классе Category, но это не помогло. Я не хочу, чтобы EF добавлял новую категорию каждый раз, когда добавляется продукт.
Ниже приведен фрагмент кода моего контроллера, представления, уровня данных и бизнес-уровня.
//Controller
public ActionResult SaveCategory(Category c)
{
AdminBusinessLayer adminBL = new AdminBusinessLayer();
adminBL.AddCategory(c);
return RedirectToAction("Index");
}
public ActionResult SaveProduct(Product p, string btnSubmit, string dpdCategories)
{
AdminBusinessLayer adminBL = new AdminBusinessLayer();
Category productCategory = new Category();
List<Category> categoryList = new List<Category>();
categoryList = adminBL.ShowCategory();
foreach (Category c in categoryList)
{
if (c.CategoryName == dpdCategories)
productCategory = c;
}
p.category = productCategory;
p.CategoryId = productCategory.Id;
adminBL.AddProduct(p);
return RedirectToAction("Index");
}
@{
ViewBag.Title = "Admin Functions";
}
@using Flipkart.ViewModels
@using Flipkart.Models
@model AdminViewModel
<form action="/Admin/SaveCategory" method="post">
<h2>Add New Category</h2>
Name: <input type="text" id="txtCategoryName" name="CategoryName" />
<br />
<br />
<input type="submit" name="btnAddCategory" value="Add Category" />
<br />
<br />
<h2>Existing Categories</h2>
<table border="1" cellpadding="5" width="20">
<tr style="background-color:yellowgreen">
<th>Id</th>
<th>Category</th>
</tr>
@foreach (Category c in Model.categoryList)
{
<tr>
<td>@c.Id</td>
<td>@c.CategoryName</td>
</tr>
}
</table>
</form>
<br />
<br />
<br />
<br />
<form action="/Admin/SaveProduct" method="post">
<h2>Add New Product</h2>
Name: <input type="text" id="txtProductName" name="ProductName" />
Category: @Html.DropDownList("dpdCategories",new SelectList(Model.categoryNames,Model))
Price: @Html.TextBox("Price")
<br />
<br />
<input type="submit" name="btnAddProduct" value="Add Product" />
<br />
<br />
<br />
<br />
<h2>Existing Products</h2>
<table border="1" cellpadding="5" width="20">
<tr style="background-color:yellowgreen">
<th>Id</th>
<th>Product</th>
</tr>
@foreach (Product p in Model.productList)
{
<tr>
<td>@p.Id</td>
<td>@p.ProductName</td>
</tr>
}
</table>
</form>
//Data Layer
public class FlipkartContext:DbContext
{
public FlipkartContext() : base("Flipkart")
{
}
public DbSet<Category> Category { get; set; }
public DbSet<Product> Product { get; set; }
public DbSet<Cart> cart { get; set; }
}
Ниже приведен бизнес-уровень, который сохраняет данные в базе данных:
//Business Layer
public void AddCategory(Category c)
{
FlipkartContext flipkartDBContext = new FlipkartContext();
flipkartDBContext.Category.Add(c);
flipkartDBContext.SaveChanges();
}
public List<Category> ShowCategory()
{
List<Category> categoryList = new List<Category>();
FlipkartContext flipkartDBContext = new FlipkartContext();
categoryList = flipkartDBContext.Category.ToList();
return categoryList;
}
public void AddProduct(Product p)
{
FlipkartContext flipkartDBContext = new FlipkartContext();
flipkartDBContext.Product.Add(p);
flipkartDBContext.SaveChanges();
}
public List<Product> ShowProduct()
{
List<Product> productList = new List<Product>();
FlipkartContext flipkartDBContext = new FlipkartContext();
productList = flipkartDBContext.Product.ToList();
return productList;
}
Комментарии:
1. Можете ли вы также добавить код класса продукта?
Ответ №1:
Проблема в том, что в каждом запросе на вашем деловом уровне вы фактически создаете новый контекст EF. Это означает, что когда вы извлекаете данные ShowCategory
методом, EF не отслеживает изменения возвращаемого Category
объекта, когда вы помещаете его в AddProduct
метод.
Обычно контекст EF используется совместно для всего одного запроса к серверу. Если вы используете только один контекст, категории не будут дублироваться.
вы должны просто поместить личное поле в свой класс бизнес-уровня
private FlipkartContext _flipkartDBContext;
и инициализируйте ее в конструкторе этого класса
_flipkartDBContext = new FlipkartContext();
и тогда вы можете просто использовать этот единственный экземпляр во всем классе
Комментарии:
1. Спасибо @jgasiorowski. Это была точная проблема. Я считаю, что упомянутый вами подход должен быть идеальной практикой. Жаль, что тренинги не охватывают это:(. Еще раз спасибо за вашу быструю помощь!!
2. @ishanmeh Это не совсем так, как это делается в решениях. Обычно люди используют для этого инъекцию зависимостей. Определенно, вам следует взглянуть на эту тему. Он широко используется, и я считаю, что он также будет полезен в ваших будущих проектах 😉