C# 通过EF更新基础查找的更好方法?
这是我的情况-我有一个DB,它有一些名为配方、配料和配方(配料)的表 食谱由1+种成分组成 配方_配料在配方和配料表之间有FKs 生成的类是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的函
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));
//使用内置哈希集函数获取要添加/删除的成分
瓦托阿德