Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
588 views
in Technique[技术] by (71.8m points)

linq to entities - Entity Framework .Where nested in .Include

I'm attempting to perform a db lookup using EF5 code-first. The basic structure and table relationships are as follows;

public partial class Member
{
    public int    RecordID {get; set;}
    public string Name     {get; set;}
    ...etc.
    public virtual ICollection<MemberLink> MasterLinks {get; set;}
    public virtual ICollection<MemberLink> SlaveLinks {get; set;}
    public virtual ICollection<Message>    ReceivedMessages {get; set;}
    public virtual ICollection<Message>    SentMessages {get; set;}
}

public partial class MemberLink
{
    public int            RecordID     {get; set;}
    public virtual Member MasterMember {get; set;}
    public virtual Member SlaveMember  {get; set;}
    ...etc.
}

public partial class Message
{
    public int            RecordID  {get; set;}
    public virtual Member Sender    {get; set;}
    public virtual Member Recipient {get; set;}
    ...etc.
}

Now, the query I'm trying to perform is using the MemberLinkRepository, and looks like;

public IList<MemberLink> GetMasterLinks(int p_MemberID)
{
    return Get()
           .Include ( memberLink => memberLink.MasterMember )
           .Include ( memberLink => memberLink.SlaveMember )
           .Include ( memberLink => memberLink.MasterMember.ReceivedMessages
                      .Where(
                      msg => msg.Sender.RecordID == memberLink.SlaveMember.RecordID) )
           .Where ( memberLink => memberLink.MasterMember.RecordID == p_MemberID)
           .ToList();

Except EF doesn't seem to like the nested Where. I could split this out into 2 separate repository calls (and indeed, it's looking like I might have to do that) but in the interest of reducing calls to the db I'm trying to do it in one foul swoop. Does anyone know how I can achieve this in one single query?

I hope the code illustrates what I'm trying to do... If not, I'll try and explain a little better.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The short answer is no, EF will not let you do that using Include().

Think about the result if it let you do this: in one case your MemberLink.MasterMember.ReceivedMessages will be fully populated, on another identical looking object MemberLink.MasterMember.ReceivedMessages is actually a sub-set of messages! What happens if you try to add to the ReceivedMessages? What if the addition doesn't match the filter? It is a bag of hurt.

The answer is to use projections:

public IList<MemberLinkWithFiltereredMessages> GetMasterLinks(int p_MemberID)
{
    return Get()
        .Include(memberLink => memberLink.MasterMember)
        .Include(memberLink => memberLink.SlaveMember)
        .Where(memberLink => memberLink.MasterMember.RecordID == p_MemberID)
        .Select(memberLink => new MemberLinkWithFilteredMessages
        {
            MemberLink = memberLink,
            FilteredMessages = memberLink.MasterMember.ReceivedMessages
                .Where(msg => msg.Sender.RecordID == memberLink.SlaveMember.RecordID)
        })
        .ToList();
}

What you are really doing is asking for a specific sub-set of information, so be explicit about it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...