试图找出在linq语句中表达以下SQL并且无处可去的正确方法。
select messageid, comment
from Message
where isactive = 1 and messageid in
(
select messageid
from org.Notification
where NotificationTypeId = 7 and orguserid in
(
select OrgUserId
from org.OrgUser
where OrgId in
(
select ChildOrgId from OrgRelation
where ParentOrgId = 10001
)
)
group by messageid
)
这在SQL Server中按原样运行,但我想在C#(E-F)代码中使用此查询,而我似乎在圈中运行。
答案 0 :(得分:2)
显然Notification
个对象有一个messageId
。多个Notification
个对象可能具有相同的MessageId
值。
我希望
Messages
的Id等于其中一个 所有MessageId
个对象的子选择的Notification
值。
首先,我将向您展示一个解决您问题的LINQ查询,然后我将告诉您有关实体框架的一些信息,这将使这种LINQ查询更易于理解和维护。
(1)选择应提取邮件的通知:
IQueryable<Notification> notificationsToUse = org.Notifications
.Where(notification => notification.TypeId == 7
&& ....);
这是你的内心选择。我不确定Notifications
,OrgUsers
和OrgRelations
之间的关系。但这不在这个问题之内。
(2)提取所有使用过的MessageIds
{/ 1>
Notifications
(3)使用“messageIdsUsedByNotificationsToUse
中的ID获取所有活动消息IQueryable<int> messageIdsUsedByNotificationsToUse = notificationsToUse
.Select(notification => notification.MessageId)
// remove duplicates:
.Distinct();
(4)您不想要完整的消息,只需要IQueryable<Message> fetchedActiveMessages = org.Messages
.Where(message => message.IsActive
&& messageIdsUsedByNotificationsToUse.Contains(message.Id));
和MessageId
Comment
TODO:如果需要:制作一个大的LINQ语句。
到目前为止,您还没有访问过该数据库。我只更改了IQueryable中的Expression。使它成为一个很大的LINQ语句不会提高性能,我怀疑它是否会提高可读性和可维护性。
似乎var result = fetchedActiveMessages.Select(message => new
{
MessageId = message.Id,
Comment = message.Comment,
});
和Message
之间存在一对多关系:每个Notification
都有零个或多个Message
,每个Notifications
属于使用外键Notification
只需一Message
。
如果您坚持entity framework code-first conventions,,那么您设计的课程类似于以下内容。 (强调一对多的关系):
MessageId
这是所有实体框架需要知道您计划class Message
{
public int Id {get; set;}
// every Message has zero or more Notifications (one-to-many)
public virtual ICollection<Notification> Notifications {get; set;}
... // other properties
}
class Notification
{
public int Id {get; set;}
// every Notifications belongs to exactly one Message using foreign key
public int MessageId {get; set;}
public virtual Message Message {get; set;}
... // other properties
}
class MyDbContext : DbContext
{
public DbSet<Message> Messages {get; set;}
public DbSet<Notification> Notifications {get; set;}
}
和Messages
之间的一对多关系。实体框架知道您打算将哪些属性作为主键和外键,并且它知道表之间的关系。
有时候有充分的理由偏离惯例。这需要使用属性或流畅的API来解决。
重要的是具有从Notifications
到Message
的虚拟ICollection以及从Notification
到它所属的Notification
的虚拟参考的结构。
如果你设计了这样的课程,你的查询将是小菜一碟:
(1)选择您要使用的通知:
Message
(2)现在您可以直接选择属于这些通知的消息:
IQueryable<Notification> notificationsToUse = ... same as above
因为每个通知只属于一条消息,所以我确定没有重复。
继续:只有活跃消息的var result = notificationsToUse.Select(notification => notification.Message)
和MessageId
Comment
我不确定 .Where(message => message.IsActive)
.Select(message => new
{
MessageId = message.Id,
Comment = message.Comment,
});
,Notifications
和OrgUsers
之间的关系。如果你设计你的类使它们代表一个正确的一对多或多对多的关系,那么即使表达式(1)也会更加简单。
答案 1 :(得分:1)
您可以将查询细分为3个不同的部分,如下所示 -
var filteredOrgUserIds = dc.OrgUsers.Where(u => dc.OrgRelations.Where(o
=>o.ParentOrgId == 10001).Select(d =>
d.ChildOrgId).ToList().Contains(u.OrgId))
.Select(uid => uid.OrgUserId)
.Distinct()
.ToList();
var filteredNotifications = dc.Notifications.Where(n =>
n.NotificationTypeId == 7 && filteredOrgUserIds.Contains(n.OrgUserId))
.Select(m => m.messageid)
.Distinct()
.ToList();
m.isactive == 1 && filteredNotifications.Contains(m.messageid))
.Select(m => new { message = m.messageid, comment = m.comment })
.Distinct()
.ToList();
这应该可行。请从您的角度尝试一次,如果有帮助请告诉我们。
答案 2 :(得分:0)
从我的Recipe转换SQL到LINQ转换为SQL:
DISTINCT
,TOP
,MIN
,MAX
等)转换为应用于整个LINQ查询的函数SELECT
字段必须替换为select new {
... }
,以创建包含所有所需字段或表达式的匿名对象。IN
翻译为.Contains()
,将NOT IN
翻译为!
... Contains()
。注意到SQL查询在使用GROUP BY
时使用DISTINCT
,然后应用配方规则:
var childOrgs = from or in OrgRelation where or.ParentOrgId == 1001 select or.ChildOrgId;
var orgUsers = from ou in OrgUser where childOrgs.Contains(ou.OrgId) select ou.OrgUserId;
var notificationMessages = (from n in Notification
where n.NotificationTypeId == 7 && orgUsers.Contains(n.orguserid)
select n.messageid).Distinct();
var ans = from m in Message
where m.isactive == 1 && notificationMessages.Contains(m.messageid)
select new { m.messageid, m.comment };
答案 3 :(得分:-1)
如果您需要使用IN子句,则应使用Contains方法。