how to retrieve id's of documents along with the documents themselves in RavenBD

185 views
Skip to first unread message

Nicolas Spontz

unread,
May 2, 2012, 1:31:10 PM5/2/12
to rav...@googlegroups.com
Is it possible, when doing a query for a certain kind of documents, to retrieve also the Ids as well as the documents themselves ?

I did not see how to do so in the documentation.
I do a plain vanilla query for now:

         use session = store.OpenSession()
         let q = session.Query<MyType>()

Daniel Lang

unread,
May 2, 2012, 1:36:19 PM5/2/12
to rav...@googlegroups.com
You should have an Id property on MyType, don't you?

Bryan Johns

unread,
May 2, 2012, 1:40:22 PM5/2/12
to rav...@googlegroups.com
Here's an example (VB):

Public Class Person
Public Property Id as Integer
Public Property Name As String
End Class

Using db as DocumentSession = store.OpenSession
dim p as New Person With {.Name = "Bobby"}
db.Store(p)
db.SaveChanges()
'at this point p.Id will be the integer value generated by RavenDB
End Using

Using db as DocumentSession = store.OpenSession
' query for entities of type Person with Name = "Bobby"
dim p As Person = db.Query(Of Person).SingleOrDefault(Function(x)
x.Name = "Bobby")
' again, p.Id will be the value generated by RavenDB when the
document was saved.
End Using

--
Bryan Johns
K4GDW
http://www.greendragonweb.com

Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.

Chris Marisic

unread,
May 2, 2012, 1:42:55 PM5/2/12
to rav...@googlegroups.com
It's always better to use string Id with RavenDB.

Nicolas Spontz

unread,
May 2, 2012, 1:59:36 PM5/2/12
to rav...@googlegroups.com
Actually, I do not have id inside the document. it is all in the "ravendb id" system from which I can Load any document

So I can perfectly retrieve one particular document using the id, and never added any field that relates to the storage : why pollute my model when ravendb handles it fine ?
Now I wanted to mass query them and store them in memory instead of picking them up one by one, hence the need to have access to the id to set up the memory association.

Daniel Lang

unread,
May 2, 2012, 2:02:00 PM5/2/12
to rav...@googlegroups.com

What? You don’t have an Id property on your model classes?

Can you please show us your classes which you store inside raven.

Bryan Johns

unread,
May 2, 2012, 2:02:46 PM5/2/12
to rav...@googlegroups.com
Why? RavenDB auto-generates the integer ID just fine.
session.Load(Of Person)(1) works just fine. Unless you want to use
something other than an integer for your primary key, a string is not
needed.

--
Bryan Johns
K4GDW
http://www.greendragonweb.com

Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.


Daniel Lang

unread,
May 2, 2012, 2:05:50 PM5/2/12
to rav...@googlegroups.com
Yes, it works. But there are some scenarios where an string is better than an integer because it's more natural to how ravendb works internally. Generally, you want to have your Id like "products/1".

Nicolas Spontz

unread,
May 2, 2012, 2:08:28 PM5/2/12
to rav...@googlegroups.com
This is the code part
   type Primitive =  | PBool      of bool
                     | PChar      of char
                     | PInt       of int
                     | PDouble    of double 
                     | PString    of string
                     | PDate      of DateTime
                     | PArray     of FieldData<Primitive> array

And this is an exemple of the JSON generated

{
  "_tag": 0,
  "Item": {
    "_tag": 6,
    "Item": [
      {
        "fieldID": "CHAIN_TICKERS",
        "value": {
          "_tag": 6,
          "Item": [
            {
              "fieldID": "Ticker",
              "value": {
                "_tag": 4,
                "Item": "SX5E 05/18/12 C2300"
              }
            }
          ]
        }
      }
    ]
  }
}

Nicolas Spontz

unread,
May 2, 2012, 2:09:27 PM5/2/12
to rav...@googlegroups.com
And the Id for this field is 

SX5EIndex/CHAIN_TICKERS

Nicolas Spontz

unread,
May 2, 2012, 2:11:37 PM5/2/12
to rav...@googlegroups.com
If you go the exemple from Ayende, he does not store any id either in his models.

The question here is, you can Load using an ID.
But can you query, get the documents back along with their ids

Chris Marisic

unread,
May 2, 2012, 2:13:21 PM5/2/12
to rav...@googlegroups.com
You lose features like the ability to query for related documents with  Session.Advanced.DatabaseCommands.StartsWith(keyPrefix, skip, take);

The corrallary to this is you lose the ability to create meaningful document keys like "users/1/profile" "users/1/shoppingcart". I found myself needing the hilo key generator almost never anymore because all of my documents generally can have semantic meaning. Some of this relates to your domain.

In my first apps with RavenDB there was nearly zero usages of Load and even to get a single document generally took a Query, in my current app there is almost no usages of anything other than Load unless Query is used to display a list of data.

If you use HiLo extensively and use INT keys, how would you load user/1's profile? You couldn't. You'd be required to do Session.Query<Profile>(x=> x.UserId = "user/1").

Daniel Lang

unread,
May 2, 2012, 2:18:54 PM5/2/12
to rav...@googlegroups.com
Nicolas, you always need to have an Id property on your classes. They are not part of the documents content, that's true. However, inside your C# or F# classes you will need a property of string or numeric type that is exactly called "Id". This is a convention which you could change if you want to have another name for that. In any case, ravendb will populate that Id property with the documents id after they are retrieved (no matter if you used Load() or Query()).

The reason why Oren isn't populating the Id property before he's saving the object in raven is that RavenDB automatically assigns id then. If your class is called "User", then raven will pluaralize that name and append a HiLo generated number like this: "users/1". If he wanted, he could have specified the id by himself, but there's no reason to do so unless you have objects which have a good natural key that is unique.

Does that make sense to you?

mvmv

unread,
May 2, 2012, 2:30:00 PM5/2/12
to rav...@googlegroups.com
a side question, where can I find all the available methods in Session.Advanced.DatabaseCommands and their usage explanation?

Daniel Lang

unread,
May 2, 2012, 2:31:52 PM5/2/12
to rav...@googlegroups.com

Nicolas Spontz

unread,
May 2, 2012, 2:32:23 PM5/2/12
to rav...@googlegroups.com
I am ready to do whatever tweak, including wrapper or whatnot.

What bugs me, is that there is already an Id field somewhere in the system (not in my classes), since I can use it when I load a document
As in

         let r = session.safeLoad<ReferenceValue>(storename)

That is what I do to retrieve my fields. No I want to memoize the whole bunch to gain a few 100's ms.
There must be a way to retrieve this already existing information, which, although semantically of no importance on the business layer, can be technically useful for stuff like preloading.

May be there is no way, and may be there is a good reason for that, but I have a hard time seeing it...

mvmv

unread,
May 2, 2012, 2:34:13 PM5/2/12
to rav...@googlegroups.com
yes, the source code is always there :)

Thanks!

Daniel Lang

unread,
May 2, 2012, 2:37:03 PM5/2/12
to rav...@googlegroups.com

Believe me, there must be an Id property on your data classes that you persist in RavenDB. That’s simply the way it works.

Please refer to the documentation here to learn more about document ids: http://ravendb.net/docs/client-api/basic-operations/saving-new-document#document-ids

 

 

 

From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On Behalf Of Nicolas Spontz
Sent: Mittwoch, 2. Mai 2012 20:33
To: rav...@googlegroups.com
Subject: Re: [RavenDB] how to retrieve id's of documents along with the documents themselves in RavenBD

 

I am ready to do whatever tweak, including wrapper or whatnot.

Chris Marisic

unread,
May 2, 2012, 2:37:35 PM5/2/12
to rav...@googlegroups.com
Session.Advanced.GetMetadataFor(document)

This will get you the full raven metadata object which I believe should include the Id.

Nicolas Spontz

unread,
May 2, 2012, 2:44:22 PM5/2/12
to rav...@googlegroups.com
Aren't you confounding the notion of 

  • an Id in the raven db system (aka, what you have in the navigation bar when you edit an Json object in the web interface) 
  • and that you object itself need to have an Id
From what I read in the document you point ot, it say "you CAN create an id property in your object", not you have to.
Which totally makes sense, as you can supply the id while storing stuff, which I do :

 session.Store(rv,storename)

Storename is then the ravenDB id, but does not exists in my model

Nicolas Spontz

unread,
May 2, 2012, 2:51:12 PM5/2/12
to rav...@googlegroups.com

Look, may be you are right, but that would be just wrong. I can't believe this would be the case.

Daniel Lang

unread,
May 2, 2012, 2:51:56 PM5/2/12
to rav...@googlegroups.com

Ok,… now I understand what you meant.

 

You can use this:

var metadata = session.Advanced.GetMetadataFor(yourObject);

var id = metadata["@id"];

 

However, I would suggest to add an Id property to your class because it’s always easier.

 

From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On Behalf Of Nicolas Spontz
Sent: Mittwoch, 2. Mai 2012 20:45
To: rav...@googlegroups.com
Subject: Re: [RavenDB] how to retrieve id's of documents along with the documents themselves in RavenBD

 

Aren't you confounding the notion of 

Oren Eini (Ayende Rahien)

unread,
May 2, 2012, 3:00:21 PM5/2/12
to rav...@googlegroups.com
You always get the ifs back
You can get them using session.Advanced.GetDocumentId

Nicolas Spontz

unread,
May 2, 2012, 3:00:55 PM5/2/12
to rav...@googlegroups.com
yes, and if I have to query them 1 by 1....
I'll just write a wrapper class

   type ravenstored<'T> = { mutable Id : string
                            ravenstored : 'T }

All those carefully killed lines of code going to waste ;)

Oren Eini (Ayende Rahien)

unread,
May 2, 2012, 3:09:24 PM5/2/12
to rav...@googlegroups.com
Intellisense

Nicolas Spontz

unread,
May 2, 2012, 3:09:35 PM5/2/12
to rav...@googlegroups.com
Very good to know !

Nicolas Spontz

unread,
May 2, 2012, 3:10:46 PM5/2/12
to rav...@googlegroups.com
what does ifs stands for ? id for storage ?

Oren Eini (Ayende Rahien)

unread,
May 2, 2012, 3:10:55 PM5/2/12
to rav...@googlegroups.com
Actually, no
You can live just fine without an I'd property 
RavenDB will manage that for you

Itamar Syn-Hershko

unread,
May 2, 2012, 3:11:04 PM5/2/12
to rav...@googlegroups.com

Daniel Lang

unread,
May 2, 2012, 3:12:00 PM5/2/12
to rav...@googlegroups.com

Uhm? How can a document not have an Id???

Itamar Syn-Hershko

unread,
May 2, 2012, 3:12:32 PM5/2/12
to rav...@googlegroups.com
Daniel, an Id _property_

Nicolas Spontz

unread,
May 2, 2012, 3:17:41 PM5/2/12
to rav...@googlegroups.com
They do have an Id, always. On the server. which you set when you store.
Not in your business class. this is optional.

Oren Eini (Ayende Rahien)

unread,
May 2, 2012, 3:20:49 PM5/2/12
to rav...@googlegroups.com
More accurate to say that you don't have to have a property Id on the entities
The document has an Id and the entity has an Id 
It is the property that is optional

Bryan Johns

unread,
May 2, 2012, 5:06:06 PM5/2/12
to rav...@googlegroups.com
Personally, I'd prefer not to have Id values like "persons/1" in my
POCO objects. I know that I'm looking at an object that came from the
"persons" collection simply by nature of the fact that I'm looking at
an instance of Person. That extra "persons/" in the Id has no real
value in any of the use cases I've encountered to date.

If I ever come across a use case where I actually need that, it could
be easily constructed at runtime.

Session.Advanced.DatabaseCommands.StartsWith(String.Format("persons/{0}",person.Id),
skip, take)

On a side note, I'm kind-of "old school". I came up in the days when
memory, persistent storage, and network bandwidth was at a premium.
My first computer only had 16k and a memory upgrade to 32k (without
voiding the warranty) required shipping the whole thing back to the
manufacturer so they could solder chips onto the circuit board.
Storing, loading, and transferring over the wire, data that isn't
needed to get the job done runs counter to my basic sensibilities and
would actually require more mental work on my part.

--
Bryan Johns
K4GDW
http://www.greendragonweb.com

Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.


Beyers

unread,
May 2, 2012, 5:48:49 PM5/2/12
to rav...@googlegroups.com
Chris,
 
The corrallary to this is you lose the ability to create meaningful document keys like "users/1/profile" "users/1/shoppingcart". I found myself needing the hilo key generator almost never anymore because all of my documents generally can have semantic meaning. Some of this relates to your domain.

I like this convention. How do you generate these keys? I assume the user document keys are set via Raven automatically (HiLo or Identity). But profile and shopping cart keys, do you manually set the Id property (e.g. profile.Id = user.Id + "/profile") or use some document key generator?

Also, how does Raven Studio handle this in its Collection window? Is it smart enough to know users/X/profile should belong to one collection?

Cheers

Beyers
 

Daniel Lang

unread,
May 2, 2012, 5:53:52 PM5/2/12
to rav...@googlegroups.com

Beyers, you probably want to look at this: http://ayende.com/blog/153704/composite-entities

 

 

From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On Behalf Of Beyers
Sent: Mittwoch, 02. Mai 2012 23:49
To: rav...@googlegroups.com
Subject: Re: [RavenDB] how to retrieve id's of documents along with the documents themselves in RavenBD

 

Chris,

Matt Warren

unread,
May 2, 2012, 6:13:44 PM5/2/12
to rav...@googlegroups.com
On Wednesday, 2 May 2012 22:06:06 UTC+1, Bryan Johns wrote:
Storing, loading, and transferring over the wire, data that isn't
needed to get the job done runs counter to my basic sensibilities and
would actually require more mental work on my part.

That's fair enough, except in this case that data is stored in the doc store and transmitted over the wire. So saving the code of deserializing it into a Id Propertly doesn't really gain you much.
 

Beyers Cronje

unread,
May 2, 2012, 6:17:12 PM5/2/12
to rav...@googlegroups.com
Thanks Daniel,

Oren's post was pretty much exactly the way I thought about using it. However again he did not touch on how he actually generates the keys in code. Is there some magic Raven call to generate composite keys automatically, or is it pretty much just convention and up to you to manually set the keys?

Daniel Lang

unread,
May 2, 2012, 6:26:14 PM5/2/12
to rav...@googlegroups.com

If I need to make an educated guess I would say that there is no eady way of having ravendb generate those ids automatically. Anyway I don’t really see the problem of appending something like “/billing” to an existing id? You can still let ravendb generate the base id like “users/1” and then have your composite it appended like “users/1/billing”, right?

 

From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On Behalf Of Beyers Cronje
Sent: Donnerstag, 03. Mai 2012 00:17
To: rav...@googlegroups.com
Subject: Re: [RavenDB] how to retrieve id's of documents along with the documents themselves in RavenBD

 

Thanks Daniel,

Bryan Johns

unread,
May 2, 2012, 6:33:32 PM5/2/12
to rav...@googlegroups.com
> -----Original Message-----
> From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On
> Behalf Of Matt Warren
>
> On Wednesday, 2 May 2012 22:06:06 UTC+1, Bryan Johns wrote:
>
> Storing, loading, and transferring over the wire, data that isn't
> needed to get the job done runs counter to my basic sensibilities
> and would actually require more mental work on my part.
>
>
>
> That's fair enough, except in this case that data is stored in the doc
> store and transmitted over the wire. So saving the code of
> deserializing it into a Id Propertly doesn't really gain you much.
>

I use an Id property, but it's almost always an integer unless I
realistically expect enough documents (or rows if I'm using an RDBMS) to
actually overflow the bounds of an integer data type on the target platform.

--
Bryan Johns
K4GDW

"The Key, the whole Key, and nothing but the Key... so help me Codd"

Daniel Lang

unread,
May 2, 2012, 6:47:10 PM5/2/12
to rav...@googlegroups.com
Bryan, in case of RavenDB you don't really save bandwidth if you choose and int32 over a int64 or long because the number will be serialized anyway, so that an id of 12345 basically has the size of a 5 character string on the wire, no matter if it will be deserialized to an int or long. I don't think it's still worth to think about such minor optimizations anymore as todays networks are always fast enough that you won't recognize it anyway.

A side note on integers being big enough for ids: If you use a HiLo with 1024 as the default value for highs, then you can only get about 2.1 million different ids using a 32bit signed integer. That is not so much. Until recently this high value was the default in case of ravendb. Now it's dynamic and typically much lower.

Oren Eini (Ayende Rahien)

unread,
May 3, 2012, 4:56:44 AM5/3/12
to rav...@googlegroups.com
While I understand that, those are very different concerns than what usually matter.
RavenDB data is compressed on both end, and the size difference wouldn't make any meaningful different for anyting that you want to do

Oren Eini (Ayende Rahien)

unread,
May 3, 2012, 4:57:34 AM5/3/12
to rav...@googlegroups.com
The default value is a capacity of 32, and it can grow.
But note that the default hilo is a long, not an int.

Bryan Johns

unread,
May 3, 2012, 7:54:03 AM5/3/12
to rav...@googlegroups.com
OK, lets approach the question from a different angle. Given the these
classes, what would be the benefit of using strings instead of integers
for the Id properties?

Public Class Person
Public Property Id As Integer
Public Property Name As String
Public Property Posts As New List(Of PostRef)

Public Class PostRef
Public Property Id As Integer
Public Property Title As String
Public Property PostedAt As DateTime
End Class
End Class

Public Class Post
Public Property Id As Integer
Public Property PostedBy As Integer
Public Property PostedAt As DateTime
Public Property Title As String
Public Property Content As String
Public Property Comments As New List(Of String)

Public Sub New()
' set the default datetime value
PostedAt = Date.UtcNow
End Sub
End Class

Other than the stuff I've already mentioned, memory usage, network
bandwidth, etc. I can think of one potentially big reason not to use
strings. You lose many of the benefits of a strongly typed language. A
POCO with a string Id field will accept pretty much anything as the Id,
even bad data that causes it to malfunction. Choosing to use a string for
any field that isn't expressly intended to hold textual data should be a
deliberate decision made in response to specific business rules and/or use
cases. That is especially true for entity Id fields.

--
Bryan Johns
K4GDW

Some people are like slinkies... not really good for anything but they
bring a smile to your face when pushed down the stairs.

> -----Original Message-----
> From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On
> Behalf Of Oren Eini (Ayende Rahien)
> Sent: Thursday, May 03, 2012 3:57 AM
> To: rav...@googlegroups.com
> Subject: Re: [RavenDB] how to retrieve id's of documents along with the
> documents themselves in RavenBD
>

Oren Eini (Ayende Rahien)

unread,
May 3, 2012, 8:11:53 AM5/3/12
to rav...@googlegroups.com
Bryan,
Readability is important. people/1 is much easier to read than 1.
More important, the argument about string vs. int with regards to OO is not really relevant - ids are opaque as far as everything is concerned.
We try to make them human readable because it make debugging easier.
Then you have the notion of semantic ids, which allows you to do some really nice things.
Sharding is also easier when you aren't limited to just ints.

Bryan Johns

unread,
May 3, 2012, 9:21:27 AM5/3/12
to rav...@googlegroups.com
I think we're running into a slight philosophical mismatch. To me;

Dim p As Person With {.Id = 1, Name = "Bob"}

is _more_ readable than;

Dim p As Person With { .Id = "people/1", .Name = "Bob"}

The extra "people/" in the Id is just noise bringing no intrinsic
value. I know I'm looking at a person. I don't need that extra text
in the Id to tell me that.

The only reason I could see a benefit to readability is possibly if
you were looking at the raw json instead of the deserialized POCO so I
I did a test last night. I stored two documents that were identical
except one had a string id and the other had an int and then looked at
them in the Raven Studio. The json was identical. So to me, unless
it meets some other business need, the string Id does more harm than
good on the client side.

With regard to semantic ids and sharding, those are among those
specific use cases I mentioned where the business rules might
necessitate considering a more complicated Id system. I still believe
that an integer Id is the best solution most of the time, especially
when you have relationships between objects. It will be my default
choice unless the specific problem being solved leads me in a
different direction.

--
Bryan Johns
K4GDW
http://www.greendragonweb.com

Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.


Chris Marisic

unread,
May 3, 2012, 3:46:57 PM5/3/12
to rav...@googlegroups.com
You were correct in your assumption that my Users document would use the standard HiLo generator.

In regards to how you generate these ids, check out my question on SO: http://stackoverflow.com/questions/9776513/is-a-data-model-driven-resource-id-a-facet-of-the-resource-or-of-the-database

I personally use string addition or string.Format inside string Id { get {, i feel my IDs are inherently part of my model and not a facet of the database. This is the polar opposite of RDBMS where keys are PURELY a facet of the db.

Chris Marisic

unread,
May 3, 2012, 3:49:50 PM5/3/12
to rav...@googlegroups.com
You keep talking about the most trivial of all cases.

How about this

Dim p As Profile With {.Id = "people/1/profile", User profile data things}

Or lets go deeper.

Dim t As Task With {.Id = "tenant/43/project/1/activityset/7/task/12", Task = "let the dog out" }

Bryan Johns

unread,
May 3, 2012, 5:00:07 PM5/3/12
to rav...@googlegroups.com
This all got started because I posted an example of a class with an
Integer id and someone else replied that string Ids are best. No
caveats of any sort were given, implying that they're the best for all
scenarios. That's simply _not_ true. I've said several times during
this discussion that I feel integer Ids are sufficient for _most_
cases and are my default choice _unless_ the business
rules/requirements indicate a need for something else.

Before I'd string together the Ids of all of an object's ancestors as
you're doing with that Task object, I'd have them as individual
properties of the Task object.

--
Bryan Johns
K4GDW
http://www.greendragonweb.com

Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.


Message has been deleted

Chris Marisic

unread,
May 4, 2012, 9:17:21 AM5/4/12
to rav...@googlegroups.com


On Thursday, May 3, 2012 5:00:07 PM UTC-4, Bryan Johns wrote:

Before I'd string together the Ids of all of an object's ancestors as
you're doing with that Task object, I'd have them as individual
properties of the Task object.


You're stuck in a RDBMS mindset and refuse to do critical thinking because of how many times you were told how to model entities for RDBMS. The best solution is both having the properties and having the rich document id.

Oren Eini (Ayende Rahien)

unread,
May 4, 2012, 9:41:44 AM5/4/12
to rav...@googlegroups.com
Bryan,
consider what happens when you are looking at something else:

Dim p as Post With { .Owner = "people/1" }

Bryan Johns

unread,
May 4, 2012, 6:07:23 PM5/4/12
to rav...@googlegroups.com
> -----Original Message-----
> From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On
> Behalf Of Chris Marisic
> Sent: Friday, May 04, 2012 8:15 AM
> To: rav...@googlegroups.com
> Subject: Re: [RavenDB] String ID vs Integer ID, was: How to retrieve
> id's of documents along with the documents themselves in RavenBD
>
>
>
> On Thursday, May 3, 2012 5:00:07 PM UTC-4, Bryan Johns wrote:
>
>
> Before I'd string together the Ids of all of an object's
> ancestors as
> you're doing with that Task object, I'd have them as individual
> properties of the Task object.
>
>
>
>
> You're stuck in a RDBMS mindset and refuse to do critical thinking
> because of how many times you were told how to model entities for
> RDBMS.

No, I simply refuse to think about the more complicated solution until I
determine that the simpler solution is insufficient.

--
Bryan Johns
K4GDW

"The shortest and surest way to live with honor in the world is to be in
reality what we would appear to be." --Socrates

Bryan Johns

unread,
May 4, 2012, 6:17:48 PM5/4/12
to rav...@googlegroups.com
The only reason I'd need to do that is if I didn't know that the .Owner
property of the Post object was a reference to a Person. I tend sprinkle
liberal quantities of XML comments on my classes, methods, and properties.

--
Bryan Johns
K4GDW

"I know no safe depository of the ultimate powers of the society but the
people themselves; and if we think them not enlightened enough to exercise
their control with a wholesome discretion, the remedy is not to take it
from them, but to inform their discretion by education." --Thomas
Jefferson
Reply all
Reply to author
Forward
0 new messages