Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.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# 通过EF更新基础查找的更好方法?_C#_Entity Framework_Entity Framework 4.1 - Fatal编程技术网

C# 通过EF更新基础查找的更好方法?

C# 通过EF更新基础查找的更好方法?,c#,entity-framework,entity-framework-4.1,C#,Entity Framework,Entity Framework 4.1,这是我的情况-我有一个DB,它有一些名为配方、配料和配方(配料)的表 食谱由1+种成分组成 配方_配料在配方和配料表之间有FKs 生成的类是recipe和component,并且recipe具有如下导航属性: 公共虚拟ICollection组件{get;set;} 很好,我知道我得到了一个生成的recipe类和一个生成的component类,recipes\u components表没有得到生成的类,因为EF仅将其视为导航属性 现在,我有一个名为SetIngredientsForRecipe的函

这是我的情况-我有一个DB,它有一些名为配方配料配方(配料)的表

食谱由1+种成分组成

配方_配料配方配料表之间有FKs

生成的类是
recipe
component
,并且
recipe
具有如下导航属性:

公共虚拟ICollection组件{get;set;}

很好,我知道我得到了一个生成的
recipe
类和一个生成的
component
类,
recipes\u components
表没有得到生成的类,因为EF仅将其视为导航属性

现在,我有一个名为
SetIngredientsForRecipe
的函数,看起来是这样的(为了简洁起见,减去try-catch代码:

public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
   using (var db = new FoodEntities(ConnectionString, null, null))
   {
      var existing = GetCurrentIngredients(recipeId);
      var toRemove = existing.Except(ingredients);
      var toAdd = ingredients.Except(existing);
      var recipe = db.recipes.Where(r => r.Id == recipeId).FirstOrDefault();
      foreach (var name in toRemove)
      {
         var entry = recipe.ingredients.Where(i => i.Name == name).FirstOrDefault();
         recipe.ingredients.Remove(entry);
      }
      foreach (var name in toAdd)
      {
         var entry = db.ingredients.Where(i => i.Name == name).FirstOrDefault();
         recipe.ingredients.Add(entry);
      }
      db.SaveChanges();
   }
}

这非常有效。

您可以使用
FirstOrDefault
调用压缩
Where
子句:

recipe.ingredients.FirstOrDefault(i => i.Name == name);
虽然我个人更喜欢使用
SingleOrDefault
,但我不确定到底有什么区别:

recipe.ingredients.SingleOrDefault(i => i.Name == name);

此外,由于传入的成分列表是一个
列表
(与成分ID列表相反),这在某种程度上意味着新成分可能也会作为该过程的一部分创建,而这一过程不会被处理(尽管为简洁起见可能会被省略).

您可以将
Where
子句压缩为
FirstOrDefault
调用:

recipe.ingredients.FirstOrDefault(i => i.Name == name);
虽然我个人更喜欢使用
SingleOrDefault
,但我不确定到底有什么区别:

recipe.ingredients.SingleOrDefault(i => i.Name == name);

此外,由于传入的成分列表是一个
列表(与成分ID列表相反),这在某种程度上意味着新成分可能也会作为该过程的一部分创建,但不会进行处理(尽管为简洁起见可能会被忽略)。

一般性能指南如下:

  • 试着处理身份证上的问题
  • 尽可能模拟实体,而不是从数据库中检索它们
  • 使用EF4的新功能,如
    Contains
    ,以简化和加速代码
基于这些原则,这里有一个针对您的问题的优化(但不是更简单)解决方案:

public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
   using (var db = new FoodEntities(ConnectionString, null, null))
   {
      var recipe = db.recipe.Single(r => r.ID == recipeId);

      // make an array since EF4 supports the contains keyword for arrays
      var ingrArr = ingredients.ToArray();

      // get the ids (and only the ids) of the new ingredients
      var ingrNew = new HasSet<int>(db.ingrediants
        .Where(i => ingrArr.Contains(i.Name))
        .Select(i => I.Id));   

      // get the ids (again only the ids) of the current receipe
      var curIngr = new HasSet<int>(db.receipes
        .Where(r => r.Id == recipeId)
        .SelectMany(r => r.ingredients)
        .Select(i => I.Id));        

      // use the build in hash set functions to get the ingredients to add / remove            
      var toAdd = ingrNew.ExpectWith(curIngr);
      var toRemove = curIngr.ExpectWith(ingrNew);   

      foreach (var id in toAdd)
      {
        // mock the ingredients rather than fetching them, for relations only the id needs to be there
        recipe.ingredients.Add(new Ingredient()
        {
          Id = id
        });
      }

      foreach (var id in toRemove)
      {
        // again mock only
        recipe.ingredients.Remove(new Ingredient()
        {
          Id = id
        });
      }

      db.SaveChanges();
   }
}
public void settingredientsforrecipe(长recipeId,列出成分)
{
使用(var db=newfoodentities(ConnectionString,null,null))
{
var recipe=db.recipe.Single(r=>r.ID==recipeId);
//创建数组,因为EF4支持数组的contains关键字
var ingrArr=配料。ToArray();
//获取新配料的ID(并且仅获取ID)
var ingrNew=新的HasSet(db.ingrediants
.Where(i=>ingrArr.Contains(i.Name))
。选择(i=>i.Id));
//获取当前receipe的ID(再次仅获取ID)
var curIngr=新的HasSet(db.receipes
.Where(r=>r.Id==recipeId)
.SelectMany(r=>r.components)
。选择(i=>i.Id));
//使用内置哈希集函数获取要添加/删除的成分
var toAdd=ingrNew.ExpectWith(curIngr);
var toRemove=居里预期(ingrNew);
foreach(toAdd中的变量id)
{
//模仿成分,而不是获取它们,因为只有id需要在那里
配方.配料.添加(新配料()
{
Id=Id
});
}
foreach(toRemove中的变量id)
{
//再次嘲笑而已
配方。配料。移除(新配料()
{
Id=Id
});
}
db.SaveChanges();
}
}
如果您想让它更简单,您可以清除所有成分,并在必要时重新添加它们,EF甚至可以聪明地发现这些关系没有改变,但不确定:

public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
  using (var db = new FoodEntities(ConnectionString, null, null))
  {    
    var recipe = db.recipe.Single(r => r.ID == recipeId);

    // clear all ingredients first
    recipe.ingredients.Clear()

    var ingrArr = ingredients.ToArray();
    var ingrIds = new HasSet<int>(db.ingrediants
      .Where(i => ingrArr.Contains(i.Name))
      .Select(i => I.Id)); 

    foreach (var id in ingrIds)
    {
      // mock the ingredients rather than fetching them, for relations only the id needs to be there
      recipe.ingredients.Add(new Ingredient()
      {
        Id = id
      });
    }

    db.SaveChanges();
  }
}
public void settingredientsforrecipe(长recipeId,列出成分)
{
使用(var db=newfoodentities(ConnectionString,null,null))
{    
var recipe=db.recipe.Single(r=>r.ID==recipeId);
//先把所有的配料都清干净
配方。配料。清爽()
var ingrArr=配料。ToArray();
var ingrIds=新的HasSet(db.Ingridiants
.Where(i=>ingrArr.Contains(i.Name))
。选择(i=>i.Id));
foreach(ingrIds中的变量id)
{
//模仿成分,而不是获取它们,因为只有id需要在那里
配方.配料.添加(新配料()
{
Id=Id
});
}
db.SaveChanges();
}
}
更新

某些编码错误已被更正。

一般性能指南如下:

  • 试着处理身份证上的问题
  • 尽可能模拟实体,而不是从数据库中检索它们
  • 使用EF4的新功能,如
    Contains
    ,以简化和加速代码
基于这些原则,这里有一个针对您的问题的优化(但不是更简单)解决方案:

public void SetIngredientsForRecipe(long recipeId, List<string> ingredients)
{
   using (var db = new FoodEntities(ConnectionString, null, null))
   {
      var recipe = db.recipe.Single(r => r.ID == recipeId);

      // make an array since EF4 supports the contains keyword for arrays
      var ingrArr = ingredients.ToArray();

      // get the ids (and only the ids) of the new ingredients
      var ingrNew = new HasSet<int>(db.ingrediants
        .Where(i => ingrArr.Contains(i.Name))
        .Select(i => I.Id));   

      // get the ids (again only the ids) of the current receipe
      var curIngr = new HasSet<int>(db.receipes
        .Where(r => r.Id == recipeId)
        .SelectMany(r => r.ingredients)
        .Select(i => I.Id));        

      // use the build in hash set functions to get the ingredients to add / remove            
      var toAdd = ingrNew.ExpectWith(curIngr);
      var toRemove = curIngr.ExpectWith(ingrNew);   

      foreach (var id in toAdd)
      {
        // mock the ingredients rather than fetching them, for relations only the id needs to be there
        recipe.ingredients.Add(new Ingredient()
        {
          Id = id
        });
      }

      foreach (var id in toRemove)
      {
        // again mock only
        recipe.ingredients.Remove(new Ingredient()
        {
          Id = id
        });
      }

      db.SaveChanges();
   }
}
public void settingredientsforrecipe(长recipeId,列出成分)
{
使用(var db=newfoodentities(ConnectionString,null,null))
{
var recipe=db.recipe.Single(r=>r.ID==recipeId);
//创建数组,因为EF4支持数组的contains关键字
var ingrArr=配料。ToArray();
//获取新配料的ID(并且仅获取ID)
var ingrNew=新的HasSet(db.ingrediants
.Where(i=>ingrArr.Contains(i.Name))
。选择(i=>i.Id));
//获取当前receipe的ID(再次仅获取ID)
var curIngr=新的HasSet(db.receipes
.Where(r=>r.Id==recipeId)
.SelectMany(r=>r.components)
。选择(i=>i.Id));
//使用内置哈希集函数获取要添加/删除的成分
瓦托阿德