views:

92

answers:

2

I'm trying to get a list of messages from the database where one of the recipients of the message matches a user. Normally, if there was only one recipient, you would have something like the following

var res = db.messages.Where(m => m.id == message_id)
               .Join(db.persons, m => m.recipients, p => p.id, (m, p) => new {m, p})
               .Select(x => new Message(){ msg = x.m, person = x.p})

But what if recipients is a comma seperated string of integers and id is an integer?

A: 

Option 1 - using Contains:

var res = from m in db.messages
          where m.id == message_id
          from p in db.persons
          where m.recipients.Split(",").Select(i => Int32.Parse(i))
                .Contains(p.id)
          select new Message() {
              msg = m,
              person = p
          };

The idea:

  1. Get the messages as in your original query
  2. Get all persons where contained in the recipient list
  3. Continue with your original query


Option 2 - using a LINQ join (maybe more complicated than it needs to be):

var res = from m in db.messages
          where m.id == message_id
          from r in m.recipients.Split(",")
          select new {
              Message = m,
              Recipient = Int32.Parse(r)
          } into rec
          join p in db.persons on rec equals p.id
          select new Message () {
              msg = m,
              person = p
          };

The idea:

  1. Get the messages as in your original query
  2. Split the string into a list of Int32
  3. Join this list against db.persons
  4. Continue with your original query


Not sure which of these is faster, you'll have to check.

I would also shy away from using comma-delimited strings as a foreign key reference namely because of the troubles you're having here. They're ugly to look at and a true pain to manipulate. Instead, if you have control over the schema, consider a one-to-many relation table having MessageId and PersonId. Of course if you don't have control, you're stuck.

Disclaimer: These are untested, so may need some tweaking for the code to work. The algorithms however should be ok.

lc
I initially oversimplified the query, it should be clearer now.
seanlinmt
it would be nice if it was in lambda syntax but I'll give that a try. And probably no need the Parse, just a .ToString() on the person id would suffice?
seanlinmt
Ok I cleaned up the end to match your select.
lc
Nope it doesn't work. I get "Comparison operators not supported for type 'System.String[]'"
seanlinmt
In that case, try the parse version?
lc
you mean you haven't tried it?
seanlinmt
Ok, I usually add the untested disclaimer but it looks like I forgot this time. I added it now.
lc
+1  A: 

You would need to convert recipients into a list of elements as a start. I'm assuming that recipients is a list of ids from the person table. As such from your question you have to pass in the person id to do a select on it?

var messages=db.messages.Select(
        m => m.id == message_id && 
        (m.recipients.Split(",").
            Any(recipient => reipient == person_id)
        )

var person = db.Persons.Select(p => p.id == person_id)

Note that doing this in linq is going to suffer a performance penalty as things like .Split are C# and will not work on IQueryable. As such the DB will have to transmit up a lot of data to perform this query depending on the size of your table. If you have a view on the database when you have tokenized this out, or you are capable of creating a new table in the DB where the recipients of a message are listed with a message ID, you could do this much more easily (not to mention normalising your DB in the process).

Spence
I'll give that a try but how do I access p ? Yes, creating a new table would be the easier alternative but I just wanted to find out if the join is possible with the existing structure.If the results are cached, then the performance penalty will be lessened?
seanlinmt
I'm also thinking that using the query syntax, using a .Contains() may just do the trick but wondering how do you do it in lambda
seanlinmt
Your query was fetching a message for given person ids? That query was this. Are you after the list of people that a given message was addressed to? That is a different query...
Spence
I'm trying to get a message which recipients contains a person id and at the same time get some information on that person. That is why I need the p
seanlinmt
BTW, There is no person_id, the only input parameter is message_id
seanlinmt
Given a message you want all the information on the people it was addressed too? That is a different question.
Spence
ok... hold on... let me just answer my own question
seanlinmt