Apparently Notification objects have a messageId. Several Notification objects may have the same value of MessageId.
I want the Messages that have an Id that equal one of the
MessageId values of a sub-selection of all Notification objects.
First I'll show you a LINQ query that solves your problem, then I'll tell you something about entity framework that would make this kind of LINQ queries easier to understand and maintain.
Direct Solution
(1) Select the notifications of whom the messages should be fetched:
IQueryable<Notification> notificationsToUse = org.Notifications
.Where(notification => notification.TypeId == 7
&& ....);
This is your inner select. I'm not sure about the relations between Notifications, OrgUsers and OrgRelations. But that is outside this question.
(2) Extract all used MessageIds of these Notifications
IQueryable<int> messageIdsUsedByNotificationsToUse = notificationsToUse
.Select(notification => notification.MessageId)
// remove duplicates:
.Distinct();
(3) Fetch all active messages with an Id in `messageIdsUsedByNotificationsToUse
IQueryable<Message> fetchedActiveMessages = org.Messages
.Where(message => message.IsActive
&& messageIdsUsedByNotificationsToUse.Contains(message.Id));
(4) You don't want the complete message, you only want the MessageId and the Comment:
var result = fetchedActiveMessages.Select(message => new
{
MessageId = message.Id,
Comment = message.Comment,
});
TODO: if desired: make one big LINQ statement.
Until now you haven't accessed the database yet. I only changed the Expression in the IQueryable. Making it one big LINQ statement won't increase performance very much and I doubt whether it would improve readability and maintainability.
Solution using possibilities of entity framework
It seems there is a one-to-many relation between Message and Notification: Every Message has zero or more Notifications, every Notification belongs to exactly one Message, using the foreign key MessageId.
If you stuck to the entity framework code-first conventions, you designed your classes similar to the following. (emphasizing the one-to-many relation):
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;}
}
This is all entity framework needs to know that you planned a one-to-many relation between Messages and Notifications. Entity framework knows which properties you intended to be the primary keys and the foreign keys, and it knows about the relation between the tables.
Sometimes there are good reasons to deviate from the conventions. This needs to be solved using attributes or fluent API.
The important thing is the structure with the virutal ICollection from Message to Notification and the virtual reference back from Notification to the Message that it belongs to.
If you've designed your classes like this, your query will be a piece of cake:
(1) Select the notifications you want to use:
IQueryable<Notification> notificationsToUse = ... same as above
(2) Now you can select the messages belonging to these Notifications directly:
var result = notificationsToUse.Select(notification => notification.Message)
Because every notification belongs to exactly one message, I'm certain there are no duplicates.
Continuing: only the MessageId and the Comment of the active messages
.Where(message => message.IsActive)
.Select(message => new
{
MessageId = message.Id,
Comment = message.Comment,
});
I wasn't sure about the relations between Notifications, OrgUsers and OrgRelations. If you design your classes such that they represent a proper one-to-many or many-to-many relation, then even expression (1) will be much simpler.