0

我有以下 linq 选择查询,它循环链接到以 B 开头的“adrianMember”的所有“Places”,我只想显示 PlaceName。我有一个从成员到地方的导航关联,但没有从地方到成员的导航关联。

using (var fdb = new FALDbContext())
{
    var adrianMember = fdb.Members.Find(1);

    foreach (string s in adrianMember.Places.Where(p=>p.PlaceName.StartsWith("B")).Select(p => p.PlaceName))
    {
        Console.WriteLine("- " + s);
    }
}

我也尝试过各种 linq 语法,例如不使用 Find ...

var adrianMember = fdb.Members.Where(m => m.MemberId == 1).FirstOrDefault();

并提供两个 linq 查询,一个用于检索成员,然后检索相关位置(并希望使 EF 进行一些延迟延迟加载),但这仍然导致 sql 效率非常低。

using (var fdb = new FALDbContext())
{
    //Need the FirstOrDefault otherwise we will return a collection (first or default will return the inner collection
    //could have multiple members with multiple places
    var members = fdb.Members.Where(m=>m.FirstName == "Bob");

    foreach (var member in members)
    {
        var places = member.Places.Where(p => p.PlaceName.StartsWith("B")).Select(p => p.PlaceName);

        foreach (var place in places)
        {
            Console.WriteLine(place);
        }
    }
}

SQL 输出获取所有行和所有列

exec sp_executesql N'SELECT 
[Extent1].[PlaceId] AS [PlaceId], 
[Extent1].[PlaceName] AS [PlaceName], 
[Extent1].[PlaceLocation] AS [PlaceLocation], 
[Extent1].[Member_MemberId] AS [Member_MemberId]
FROM [dbo].[Places] AS [Extent1]
WHERE [Extent1].[Member_MemberId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

有没有办法将 sql 限制为类似

SELECT PlaceName FROM Places WHERE MemberId = 1 AND PlaceName like 'B%'

我的项目中有几种情况,上面生成的 sql 会使查询太慢(每个成员 20,000 条记录超过 20 列)。如果我确实有更多记录,linq 是否足够聪明以进行更改?

4

2 回答 2

2

试试这个:

using (var fdb = new FALDbContext()) 
{     
    var members = fdb.Members.Where(m=>m.FirstName == "Bob");      
    foreach (var member in members)     
    {         
        fdb.Places.Where(p => p.PlaceName.StartsWith("B") && p.MemberId == member.Id).Select(p => p.PlaceName);
        foreach (var place in places)         
        {             
            Console.WriteLine(place);         
        }     
    } 
} 

这里有一个类似的问题

于 2012-07-07T19:14:18.753 回答
0

在解决这个问题一个月后,我想我会再看一眼......

首先,我不确定我想要实现什么!!!但是,我似乎确实找到了一些我想要的有趣且更有效的 sql 查询。

我的第一个选择是使用 Entry & Collection 方法使用显式加载。这将创建一个 SQL 查询来检索每个相应的 Place 记录,并且重要的是,投影我想要的列(只是描述)并限制行(那些以 L 开头的 Places)。如果我有很多关联的地方,这确实会创建很多查询,但是如果我不知道要检索哪些地方,我可以即时执行此操作。

    using (var fdb = new FALDbContext())
    {
        foreach (var member in fdb.Members)
        {
            var places = fdb.Entry(member)
                            .Collection(m => m.Places)
                            .Query()
                            .Where(p => p.PlaceName.StartsWith("L"))
                            .Select(p => p.PlaceName);

            foreach (var place in places)
            {
                Console.WriteLine(place);
            }
        }
    }

第二个选项是使用延迟加载,但指定严格控制的 LINQ to Entities 位。

这会进入数据库一次,只检索我想要的成员和项目,并限制两个表以及一个可爱高效的 sql 查询!

    using (var fdb = new FALDbContext())
    {
        var myList = fdb.Members
                            .Where(m => m.GenderShareWithId > 0)
                            .Select(m => new { m.MemberId, m.DisplayName, Places = m.Places.Where(p => p.PlaceName.StartsWith("L")).Select(p => p.PlaceName) });

        foreach (var item in myList)
        {
            Console.WriteLine(item.DisplayName);
            foreach (var place in item.Places)
            {
                Console.WriteLine(" - " + place);
            }
        }
    }


SELECT 
    [Extent1].[MemberId] AS [MemberId], 
    [Extent1].[DisplayName] AS [DisplayName], 
    [Extent2].[PlaceName] AS [PlaceName]
FROM  [dbo].[Members] AS [Extent1]
LEFT OUTER JOIN [dbo].[Places] AS [Extent2] 
    ON ([Extent1].[MemberId] = [Extent2].[Member_MemberId]) AND ([Extent2].[PlaceName] LIKE N'L%')
WHERE [Extent1].[GenderShareWithId] > 0
于 2012-08-07T00:05:57.603 回答