0

在 MVC 3 项目中使用 Linq to Entity(实体框架)。

我的模型:

表 - 用户用户
ID (PK)
...

表 - 客户
C​​lientID (PK)

表 - PropertyItems
PropertyItemID (PK)

表 - MemberContactPreference(包含用户选择的 PropertyItems - 多对多)
UserID(FK)
PropertyItemID(FK)

表 ClientProperties(包含属于 Clients 的 PropertyItems - 多对多)
ClientID (FK)
PropertyItemID (FK)

我想列出所有选择了客户选择的所有属性的不同用户。

我的方法:

我得到了一个特定客户的所有属性的列表

Iqueryable<ClientProperty> clientProperties  = GetClientProperties(ClientID)

Iqueryable<User> UsersMatchingClientProperties = GetAllUsers();



foreach (ClientProperty property in clientproperties)
{

 UsersMatchingClientProperties = (from uem in UsersMatchingClientProperties
                                  join ucp in GetAllMemberContactPreferences on 
                                  ucp.UserID == uem.UserID
                                  where uem.MemberContactPreferences.SelectMany(      
                                  mcp => mcp.PropertyItemID == property.PropertyItemID)
                                  select uem).Distinct;
}

它只第一次给出正确的结果。因为它不会在每次迭代时减少 UsersMatchingClientProperties 中的项目数。实际上它用新的结果集替换了集合。我想在每次迭代中过滤掉这个集合。

此外,在不使用 Linq 的情况下在 Lambda 表达式中执行此操作的任何建议。

谢谢

4

2 回答 2

1

在 for 循环中生成 iqueryable 似乎是一件危险的事情,最终可能会导致一次执行的怪物 sql join。

无论如何,我认为你不需要那个。这样的事情怎么样?

// for a given client, find all users 
// that selected ALL properties this client also selected

Iqueryable<ClientProperty> clientProperties  = GetClientProperties(ClientID)

Iqueryable<User> allUsers= GetAllUsers();

Iqueryable<MemberContactPreference> allMemberContactProperties = GetAllMemberContactPreferences();


Iqueryable<User> UsersMatchingClientProperties = allUsers
.Where(user => allMemberContactProperties
               .Where(membP => membP.UserID==user.UserID)
               .All(membP => clientProperties
                           .Select(clientP => clientP.PropertyID)
                           .Contains(membP.PropertyID)
               )
);

这是一个替代查询,以防您希望用户为给定客户端选择 ANY 属性

// for a given client, find all users 
// that selected ANY properties this client also selected

Iqueryable<ClientProperty> clientProperties  = GetClientProperties(ClientID)

Iqueryable<User> allUsers= GetAllUsers();

Iqueryable<MemberContactPreference> allMemberContactProperties = GetAllMemberContactPreferences();


Iqueryable<User> UsersMatchingClientProperties = clientproperties
.Join(allMembersContactProperties, // join clientproperties with memberproperties
      clientP => clientP.PropertyItemID, 
      membP   => membP.PropertyItemID,
      (clientP, membP) => membP)) // after the join, ignore the clientproperties, keeping only memberproperties
.Distinct()                       // distinct is optional here. but perhaps faster with it?
.Join(allUsers,                   //join memberproperties with users
      membP => membP.UserID,
      user  => user.UserID,
      (membP, user) => user))     // after the join, ignore the member properties, keeping only users 
.Distinct();
于 2012-05-12T09:03:26.790 回答
1

我相信 Hugo 在建议改进查询的方法方面做得很好(+1)。但这还不能解释问题的原因,即修改后的关闭陷阱。

我认为在你的循环之后,有一些代码实际上在UsersMatchingClientProperties. 在那一刻,使用循环变量的最后一个值property执行查询!(循环变量是在迭代中创建的每个查询委托中的闭包,并且每次迭代都会对其进行修改)。

像这样改变循环:

foreach (ClientProperty property in clientproperties)
{
    var property1 = property;
    ...

并在查询中使用 property1。那应该可以解决问题的原因。但如前所述,看起来整个过程可以改进。

于 2012-05-12T13:32:43.820 回答