MongoDB
Create
11 samples, from the least code that works to complete workflows.
What a create does
| Rule | On MongoDB |
|---|---|
| Where it goes | The entity's name is the collection; MongoDB makes a collection on its first insert |
| The id | The declared id is the document's _id, named in your code by its declared column (account_id) |
| A generated string id | An ObjectId ARX makes before the insert, returned as its 24-character text |
| A generated Guid id | A version 7 Guid ARX makes (new ids sort by time) |
| A generated number id | Refused (ARX8001): MongoDB has no sequences |
No id (NoIdColumn) |
Refused (ARX1001): every MongoDB document has an _id |
| A duplicate | ARX3001 UniqueViolation, naming the index; a plain insert never replaces a document |
| Names | ASCII letters, digits and _; a $ or SQL syntax is ARX1017; field names keep their case |
| Without a catalog | Not resolved: a collection has no declared id to read, so a table the catalog (or entity.IdColumn) doesn't declare stays ARX1016 IdNotDeclared. The SQL providers resolve it (capability SchemaResolution, which MongoDB doesn't declare) |
Reference
Value types
| .NET value | Stored as |
|---|---|
string, char |
string |
a plain enum |
refused (ARX1007): write (int)value or value.ToString(), or use a selection set |
int, short, byte |
32-bit integer |
long, uint |
64-bit integer |
decimal |
Decimal128 (exact) |
double, float |
double (NaN and infinity allowed) |
bool |
boolean |
Guid |
binary subtype 4 (UUID) |
byte[], ArxBytea |
binary |
ArxJsonB |
an embedded document or array (its JSON parsed) |
| an array or a list | an array of the values above |
ArxSelectionSetValue |
its code, or an array of codes |
ArxEntityReference |
the referenced id, as the referenced collection stores it (an ObjectId for a generated string id) |
null |
null |
Dates and times
| .NET value | Stored as |
|---|---|
DateTime (UTC) |
a BSON date, to the millisecond: finer ticks are dropped |
DateTime (Local) |
converted to UTC |
DateTime (Unspecified) |
taken as UTC |
DateTimeOffset |
its UTC instant (the offset isn't kept) |
DateOnly |
midnight UTC of that day |
TimeOnly, TimeSpan |
text (09:30:00.0000000, 1.02:03:04) |
default(DateTime), default(DateTimeOffset), default(DateOnly) |
refused (ARX1013): they mean "not set" |
The samples
Basics
The least code that works.
1Create one record and get its idProgressiveThe smallest create: one document, in four scenarios. The usual way first (the id declared in the schema, an ObjectId ARX makes), then the id declared on the entity, then an id you supply, then a Guid id.
A document that refers to another: a contact of an account, in two scenarios. The reference is an ArxEntityReference made from the id CreateAsync returned; one to a collection the schema doesn't declare is refused before anything is sent.
The errors a create meets most, in three scenarios: a duplicate (a unique index), a value ARX refuses before sending anything, and an id MongoDB can't make.
Real cases
What an application does: a small CRM and product catalogue.
1Store every kind of valueProgressiveWhat each .NET value becomes in MongoDB, in three scenarios: numbers, text and flags; dates and times; and the shapes a document can hold, an embedded document, an array and a picklist with several choices.
A form whose fields become attributes, attacked in three ways: a field named like a MongoDB operator, a field named with SQL in it, and a value that looks like an operator.
Advanced cases
Dependency injection, transactions, batch scopes and setting the service up.
1Create in an ARX transactionAdvancedSeveral calls in one ARX transaction, in two scenarios: an account and its contacts committed together, and a transaction a failed call aborts, so nothing of it is stored.
A security check around every create (SecurityGuard, in the project root), in four scenarios: a normal request passes through; an attack is logged and the user sees a plain message; repeated attacks block the user; and a false positive, a harmless file header flagged as SQL, is triaged and fixed without blocking anyone.
The service set up from the database instead of by hand, in three scenarios: preload a collection at startup, create through the preloaded service, and Strict, where only the preloaded fields may be written.
Set the service up for production, in three scenarios: depend on IArxDataService, check the server at startup, and trace and measure every call.
Use documents whose fields are named outside ARX's name rule, in three scenarios: declare an alias for each such field and create documents through them, read and query by the aliases, and see what is still refused: the field's own name in a call, and a field name MongoDB would read as a path.
Log every ARX call through ILogger, in three scenarios: one line per call with its table and how long it took, a failed call with its ARX code (and the exception logged where it is caught), and only the calls worth keeping in production.