让我先说这是自学,我正在尝试自学LINQ和实体框架。我花了几天时间试图将这个问题底部的SQL语句转换为LINQ,结果很糟糕。我还在底部包含了SQL图表。
我的目标是选择与传入的字符串数组具有相同字符的所有故事。我不想要返回有额外字符或缺少字符的故事。到目前为止,这是我虚弱的LINQ技能:
var characters = new string[] { "Harry", "Tom" };
var cq = _context.TblCharacter.AsNoTracking().Where(c => characters.Contains(c.NameVc));
var q = from c in cq
join sc in _context.TblStoryCharacter.AsNoTracking()
on c.IdI equals sc.CharacterIdI
join s in _context.TblStory.AsNoTracking().Include(s => s.TblStoryCharacter).ThenInclude(sc => sc.CharacterIdINavigation)
on sc.StoryIdI equals s.IdI
where s.TblStoryCharacter.Count() == characters.Length
where s.TblStoryCharacter.Where(sc => characters.Contains(sc.CharacterIdINavigation.NameVc)).Count() == characters.Length
select s;
上面的代码产生了一堆查询(下面的SQL profiler图片),并将一堆对象加载到内存中。这种情况有没有LINQ魔力?
LINQ衍生了查询:
SELECT [t0].[StoryId_i]
FROM [tbl_story_character] AS [t0]
SELECT [sc1].[StoryId_i]
FROM [tbl_story_character] AS [sc1]
INNER JOIN [tbl_character] AS [sc.CharacterIdINavigation0] ON [sc1].[CharacterId_i] = [sc.CharacterIdINavigation0].[Id_i]
WHERE [sc.CharacterIdINavigation0].[Name_vc] IN ('Harry', 'Tom')
这是我开始尝试转换为LINQ的SQL:
select *
from tbl_story
where Id_i in (
select sc.StoryId_i
from tbl_story_character sc
inner join tbl_character c
on c.Id_i = sc.CharacterId_i
where c.Name_vc in ('Harry', 'Tom')
and not exists (
select *
from tbl_story_character subsc
inner join tbl_character subc
on subc.Id_i = subsc.CharacterId_i
where subc.Name_vc not in ('Harry', 'Tom')
and subsc.StoryId_i = sc.StoryId_i
)
group by sc.StoryId_i
having count(*) = 2
)
编辑: 模型由EFCore基于现有数据库生成,每个模型都包含基于图中外键的导航属性。
在接受Jon Skeet和Munzer的建议后,新的LINQ。
from s in _context.TblStory.AsNoTracking()
.Include(s => s.AuthorIdINavigation)
.Include(s => s.TblStoryCharacter)
.ThenInclude(sc => sc.CharacterIdINavigation)
where s.TblStoryCharacter.All(sc => characters.Contains(sc.CharacterIdINavigation.NameVc))
where s.TblStoryCharacter.Count == 2
select s;
这导致以下SQL似乎是正确的。
SELECT [s].[Id_i], [s].[AuthorId_i], [s].[Published_dt]
FROM [tbl_story] AS [s]
INNER JOIN [tbl_author] AS [t2] ON [s].[AuthorId_i] = [t2].[Id_i]
WHERE NOT EXISTS (
SELECT 1
FROM [tbl_story_character] AS [sc]
INNER JOIN [tbl_character] AS [sc.CharacterIdINavigation] ON [sc].[CharacterId_i] = [sc.CharacterIdINavigation].[Id_i]
WHERE ([s].[Id_i] = [sc].[StoryId_i]) AND [sc.CharacterIdINavigation].[Name_vc] NOT IN ('Harry', 'Tom')) AND ((
SELECT COUNT(*)
FROM [tbl_story_character] AS [t]
WHERE [s].[Id_i] = [t].[StoryId_i]
) = 2)
ORDER BY [s].[Id_i]
答案 0 :(得分:2)
我相信All就是你在这里寻找的
它应该是这样的
var q = from c in cq
join sc in _context.TblStoryCharacter.AsNoTracking()
on c.IdI equals sc.CharacterIdI
join s in _context.TblStory.AsNoTracking().Include(s => s.TblStoryCharacter).ThenInclude(sc => sc.CharacterIdINavigation)
on sc.StoryIdI equals s.IdI
where s.TblStoryCharacter.All(sc => characters.Contains(sc.CharacterIdINavigation.NameVc))
select s;
答案 1 :(得分:0)
尝试这样的事情:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] names = {"Harry", "Tom"};
var results = (from sc in Story_Character.story_character
join chr in Character.character on sc.Id_i equals chr.Id_i
join st in Story.story on sc.Id_i equals st.Id_i
join auth in Author.author on sc.Id_i equals auth.Id_i
where names.Contains(chr.Name_vc)
select new { sc = sc, chr = chr, st = st, auth = auth })
.GroupBy(x => x.sc.StoryId_i).Where(x => x.Count() >= 2).ToList();
}
}
public class Story_Character
{
public static List<Story_Character> story_character = new List<Story_Character>();
public int Id_i { get; set; }
public int StoryId_i { get; set; }
public int CharacterId_i { get; set; }
}
public class Character
{
public static List<Character> character = new List<Character>();
public int Id_i { get; set; }
public string Name_vc { get; set; }
}
public class Story
{
public static List<Story> story = new List<Story>();
public int Id_i { get; set; }
public DateTime Published_dt { get; set; }
public string Title_vc { get; set; }
public string AuthorId_i { get; set; }
}
public class Author
{
public static List<Author> author = new List<Author>();
public int Id_i { get; set; }
public string Name_vc { get; set; }
public string Url_vc { get; set; }
}
}