Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多对多关系基本示例(MVC3)_C#_Asp.net Mvc 3_Entity Framework 4_Scaffolding_Sql Server Ce 4 - Fatal编程技术网

C# 多对多关系基本示例(MVC3)

C# 多对多关系基本示例(MVC3),c#,asp.net-mvc-3,entity-framework-4,scaffolding,sql-server-ce-4,C#,Asp.net Mvc 3,Entity Framework 4,Scaffolding,Sql Server Ce 4,我有一个MVC3 C项目,我有一个FoodItem和FoodItemCategory的模型。这两个模型如下所示: public class FoodItem { public int ID { get; set; } [Required] public string Name { get; set; } public string Description { get; set; } public virtual ICollection<FoodIte

我有一个MVC3 C项目,我有一个FoodItem和FoodItemCategory的模型。这两个模型如下所示:

public class FoodItem
{
    public int ID { get; set; }
    [Required]
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<FoodItemCategory> Categories { get; set; }
    public DateTime CreateDate { get; set; }
}

public class FoodItemCategory {
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public virtual ICollection<FoodItem> FoodItems { get; set; }
    public DateTime CreateDate { get; set; }
} 
公共类FoodItem
{
公共int ID{get;set;}
[必需]
公共字符串名称{get;set;}
公共字符串说明{get;set;}
公共虚拟ICollection类别{get;set;}
公共日期时间CreateDate{get;set;}
}
公共类食品分类{
公共int ID{get;set;}
公共字符串名称{get;set;}
公共字符串说明{get;set;}
公共虚拟ICollection FoodItems{get;set;}
公共日期时间CreateDate{get;set;}
} 
我有一个_CreateOrEdit.cshtml视图,它最初是从架子工生成的,我对它进行了修改,以包含所有类别,并选中食品所属的框。一种食物可以有许多或所有的类别。该视图如下所示:

@model StackOverFlowIssue.Models.FoodItem
<div class="editor-label">
    @Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Name)
    @Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
    @Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Description)
    @Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
    @Html.LabelFor(model => model.Categories)
</div>
<div class="editor-field">
    @foreach (var FoodItemCategory in (IEnumerable<StackOverFlowIssue.Models.FoodItemCategory>)ViewBag.Categories){
        <input type="checkbox" name="FoodItemCategoryId" value="@FoodItemCategory.ID" 
        @foreach(var c in Model.Categories){
            if(c.ID == FoodItemCategory.ID){ 
                @String.Format("checked=\"checked\"")
            } 
        } 
        />
        @FoodItemCategory.Name 
        <br />
    } 
</div>
@Html.Hidden("CreateDate", @DateTime.Now)
    [HttpPost]
    public ActionResult Edit(FoodItem foodItem)
    {
        if (ModelState.IsValid)
        {
            var cList = Request["CategoryId"].Split(',');
            List<FoodItemCategory> categories = new List<FoodItemCategory>();

            foreach (var c in cList) {
                var ci = Convert.ToInt32(c);
                FoodItemCategory category = context.FoodItemCategories.Single(x => x.ID == ci);
                categories.Add(category);
            }

            context.Entry(foodItem).State = EntityState.Modified;
            restaurant.Categories = categories;
            context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(foodItem);
    }
@model StackOverFlowIssue.Models.FoodItem
@LabelFor(model=>model.Name)
@EditorFor(model=>model.Name)
@Html.ValidationMessageFor(model=>model.Name)
@LabelFor(model=>model.Description)
@EditorFor(model=>model.Description)
@Html.ValidationMessageFor(model=>model.Description)
@LabelFor(model=>model.Categories)
@foreach(在(IEnumerable)ViewBag.Categories中的变量FoodItemCategory){
@FoodItemCategory.Name

} @Html.Hidden(“CreateDate”,@DateTime.Now)
如您所见,我有一个嵌套循环,为每个类别创建一个复选框,在创建每个类别时,我在模型的Categories属性中循环并检查该特定类别。如果它存在,我设置复选框的checked属性。如果选中一个框并单击保存,则在控制器上的HttpPost操作上,我将执行以下操作:

@model StackOverFlowIssue.Models.FoodItem
<div class="editor-label">
    @Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Name)
    @Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
    @Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Description)
    @Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
    @Html.LabelFor(model => model.Categories)
</div>
<div class="editor-field">
    @foreach (var FoodItemCategory in (IEnumerable<StackOverFlowIssue.Models.FoodItemCategory>)ViewBag.Categories){
        <input type="checkbox" name="FoodItemCategoryId" value="@FoodItemCategory.ID" 
        @foreach(var c in Model.Categories){
            if(c.ID == FoodItemCategory.ID){ 
                @String.Format("checked=\"checked\"")
            } 
        } 
        />
        @FoodItemCategory.Name 
        <br />
    } 
</div>
@Html.Hidden("CreateDate", @DateTime.Now)
    [HttpPost]
    public ActionResult Edit(FoodItem foodItem)
    {
        if (ModelState.IsValid)
        {
            var cList = Request["CategoryId"].Split(',');
            List<FoodItemCategory> categories = new List<FoodItemCategory>();

            foreach (var c in cList) {
                var ci = Convert.ToInt32(c);
                FoodItemCategory category = context.FoodItemCategories.Single(x => x.ID == ci);
                categories.Add(category);
            }

            context.Entry(foodItem).State = EntityState.Modified;
            restaurant.Categories = categories;
            context.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(foodItem);
    }
[HttpPost]
公共行动结果编辑(FoodItem FoodItem)
{
if(ModelState.IsValid)
{
var cList=Request[“CategoryId”].Split(',');
列表类别=新列表();
foreach(cList中的var c){
var ci=转换为32(c);
FoodItemCategory category=context.FoodItemCategories.Single(x=>x.ID==ci);
类别。添加(类别);
}
context.Entry(foodItem).State=EntityState.Modified;
餐厅。类别=类别;
SaveChanges();
返回操作(“索引”);
}
返回视图(foodItem);
}
我可以保存一次类别。如果我返回视图,只需单击“保存”,我将收到以下错误:

无法将重复值插入到唯一索引中。[表名=>FoodItemCategoryFoodItems,约束名称=PK\u FoodItemCategoryFoodItems\u00000000000000 A8] 描述:执行当前web请求期间发生未处理的异常。请>查看堆栈跟踪以了解有关错误的更多信息以及错误在代码中的起源

异常详细信息:System.Data.SqlServerCe.SqlCeException:无法将重复值插入到>唯一索引中。[表名=FoodItemCategoryFoodItems,约束名称=>PK\u FoodItemCategoryFoodItems\u00000000000000 a8]

源错误:

第97行:context.Entry(foodItem).State=EntityState.Modified; 第98行:foodItem.Categories=类别; 第99行:context.SaveChanges(); 第100行:返回重定向操作(“索引”); 第101行:}

不确定这是否重要,但我使用的是SQLServer Compact Edition 4。我这样做对吗?对于这样的东西,通常的编码实践是什么?我知道同样的情况每天都会发生,因为同样的关系模型在很多情况下都会用到,比如博客等。

尝试类似的方法(未经测试):

这看起来效率很低,但因为您处理的是多对多关系,可以在视图中添加或删除关系,所以这是唯一的方法。原因是:

  • 您必须说明添加了哪些关系,删除了哪些关系
  • 如果只添加所有相关类别,则再次插入关系
  • 您不能说删除了哪些关系,因为您不传输有关未选中类别的信息
有关分离对象图和处理关系的更多信息,请参阅。这是关于ObjectContext API的,但DbContext API只是一个包装,因此同样的限制仍然存在。

尝试类似的方法(未经测试):

这看起来效率很低,但因为您处理的是多对多关系,可以在视图中添加或删除关系,所以这是唯一的方法。原因是:

  • 您必须说明添加了哪些关系,删除了哪些关系
  • 如果只添加所有相关类别,则再次插入关系
  • 您不能说删除了哪些关系,因为您不传输有关未选中类别的信息

有关分离对象图和处理关系的更多信息,请参阅。这是关于ObjectContext API的,但DbContext API只是一个包装器,因此同样的限制仍然存在。

除了Ladislav的答案之外,您还可以使用以下方法来摆脱请求[].split()部分:

[HttpPost]
public ActionResult Edit(FoodItem foodItem, ICollection<int> CategoryId)
{
    if (ModelState.IsValid)
    {
        int id = foodItem.Id;
        // Load food item with related categories first
        var item = context.FoodItems
                          .Include(f => f.Categories)
                          .Single(f => f.Id == id);

        // Process changed scalar values
        context.Entry(item).CurrentValues.SetValues(foodItem);

        // Brute force processing of relations
        // This can be optimized - instead of deleting all and adding all again
        // you can manually compare which relations already exists, add new and
        // remove non existing but let's make that as a homework
        item.Categories.Clear();

        foreach (var id in CategoryID) 
        {
            // Use find - if category was already loaded in the first query, it will
            // be reused without additional query to DB
            var category = context.Categories.Find(id);
            // Now add category to attached food item to create new relation
            item.Categories.Add(category);
        }

        context.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(foodItem);
}
[HttpPost]
公共操作结果编辑(FoodItem FoodItem,ICollection类别ID)
{
if(ModelState.IsValid)
{
int id=foodItem.id;
//首先加载具有相关类别的食品
var item=context.FoodItems
.包括(f=>f.类别)
.Single(f=>f.Id==Id);
//处理更改的标量值
context.Entry(item).CurrentValues.SetValues(foodItem);
//计算机的蛮力处理