У меня возникают проблемы при попытке конвертировать мои несколько вложенных циклов в выражение лямбда или linq. Я думаю, что мне сложно понять, как правильно обращаться к свойствам при использовании методов.All или.Contains. В любом случае, помощь приветствуется. (Я прочитал несколько других сообщений по этому вопросу, но я все еще изо всех сил пытаюсь заставить его работать.)
Вот как выглядят классы:
public class RecipeSearch
{
public List<Recipe> Recipe { get; set; }
public List<Meal> MealSettings { get; set; }
public List<Ingredient> MainIngredient { get; set; }
}
public class Meal
{
public int Id { get; set; }
public bool Value { get; set; }
public string DisplayName { get; set; }
}
public class MainIngredient
{
public int Id { get; set; }
public bool Value { get; set; }
public string DisplayName { get; set; }
}
Здесь вложенный цикл:
IEnumerable<Recipe> recipeList = dbContext.Recipes
.OrderBy(r => r.name)
.Where(r => r.name.Contains(name) || string.IsNullOrEmpty(name))
.ToList();
//Model object is of type RecipeSearch
IEnumerable<Meal> selectedMeals = model.MealSettings.Where(x => x.Value == true);
IEnumerable<MainIngredient> selectedIngredients = model.MainIngredient.Where(x => x.Value == true);
foreach (var selected in recipeList) //loop through the master list
{
foreach (var item in selectedMeals) //loop through selected meal categories
{
if (selected.mealCategoryId == item.Id) //passed the meal category check (i.e. it exists)
{
foreach (var ingredient in selectedIngredients) // selected master ingredients
{
if (selected.Ingredients.Any(x => x.SubCategory.mainCategoryid == ingredient.Id))
{
recipe.Recipe.Add(selected);
break;
}
}
}
}
}
Я полагаю, что следует отметить, что цикл работает полностью, как ожидалось. Я просто думаю, что он лямбда /linq более чист для чтения.
EDIT: Вот другие объекты:
public partial class Recipe
{
public Recipe()
{
Directions = new HashSet<Direction>();
Images = new HashSet<Image>();
Ingredients = new HashSet<Ingredient>();
Nutritions = new HashSet<Nutrition>();
Ratings = new HashSet<Rating>();
}
public int recipeId { get; set; }
//Removed other properties that are not relevant
public virtual ICollection<Ingredient> Ingredients { get; set; }
public virtual MealCategory MealCategory { get; set; }
public virtual RecipeStatus RecipeStatus { get; set; }
}
public partial class Ingredient
{
public int ingredientId { get; set; }
public int? recipeId { get; set; }
public int? subCategoryId { get; set; }
public int measurementId { get; set; }
public int amount { get; set; }
public virtual Recipe Recipe { get; set; }
public virtual SubCategory SubCategory { get; set; }
public virtual Measurement Measurement { get; set; }
}
public partial class SubCategory
{
public SubCategory()
{
Ingredients = new HashSet<Ingredient>();
}
public int subCategoryId { get; set; }
[Required]
[StringLength(255)]
public string name { get; set; }
public int? mainCategoryid { get; set; }
public virtual ICollection<Ingredient> Ingredients { get; set; }
public virtual Maincategory Maincategory { get; set; }
}
Будет ли это работать?
var query = from selected in receipeList
join item in selectedMeals on selected.MealCategoryId equals item.Id
where selected.Ingredients.Select(x => x.SubCategory.mainCategoryid.Value)
.Intersect(selectedIngredients.Select(s => s.Id)).Count() > 0
select selected;
foreach(var sel in query)
recipe.Recipe.Add(sel);
Я не вижу, где вы получаете recipe.Recipe
от.
В основном, чтобы помочь вам перевести это в linq и настроить, как вы хотите:
Эта:
foreach (var selected in recipeList) //loop through the master list
{
foreach (var item in selectedMeals) //loop through selected meal categories
{
if (selected.mealCategoryId == item.Id) //passed the meal category check (i.e. it exists)
{
}
}
}
Переводит на соединение так:
from selected in receipeList
join item in selectedMeals on selected.MealCategoryId equals item.Id
Кроме того, эти строки:
if (selected.Ingredients.Any(x => x.SubCategory.mainCategoryid == ingredient.Id))
{
recipe.Recipe.Add(selected);
break;
}
Можно перевести на:
where selected.Ingredients.Select(x => x.SubCategory.mainCategoryid.Value)
.Intersect(selectedIngredients.Select(s => s.Id)).Count() > 0
select selected;
//and then
foreach(var sel in query)
recipe.Recipe.Add(sel);
Обратите внимание на следующую часть,
IEnumerable<Recipe> recipeList = dbContext.Recipes
.OrderBy(r => r.name)
.Where(r => r.name.Contains(name) || string.IsNullOrEmpty(name))
.ToList();
2 вещи пахнут здесь: во-первых, вы должны поменять or-condition, чтобы сначала проверить String.IsNullOrEmpty, а затем поставить там, где перед порядком, чтобы уменьшить элементы, которые нужно заказать.
IEnumerable<Recipe> recipeList = dbContext.Recipes
.Where(r => string.IsNullOrEmpty(name) || r.name.Contains(name))
.OrderBy(r => r.name)
.ToList();
В зависимости от ItemCount это может дать вам довольно "импульс".
Intersect
вместо двух операторовAny
. Кроме того,ForEach
определен только вList<T>
не вIEnumerable<T>
поэтому я изменил его на обычныйforeach
.