Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dj-nitehawk committed Nov 29, 2023
1 parent 6ccac9a commit 7854a2f
Show file tree
Hide file tree
Showing 119 changed files with 44,354 additions and 44,049 deletions.
1 change: 0 additions & 1 deletion Documentation/.vscode/spellright.dict

This file was deleted.

54 changes: 39 additions & 15 deletions Documentation/wiki/Entities.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class Book : Entity

if there are some properties on entities you don't want persisted to mongodb, simply use the `IgnoreAttribute`.
you can prevent null/default values from being stored with the use of `IgnoreDefaultAttribute`.

```csharp
public class Book : Entity
{
Expand All @@ -27,7 +28,9 @@ public class Book : Entity
```

# Customize field names

you can set the field names of the documents stored in mongodb using the `FieldAttribute` like so:

```csharp
public class Book
{
Expand All @@ -37,7 +40,9 @@ public class Book
```

# Customize collection names

by default, mongodb collections will use the names of the entity classes. you can customize the collection names by decorating your entities with the `CollectionAttribute` as follows:

```csharp
[Collection("Writer")]
public class Author : Entity
Expand All @@ -47,7 +52,9 @@ public class Author : Entity
```

# Optional auto-managed properties

there are 2 optional interfaces `ICreatedOn` & `IModifiedOn` that you can add to entity class definitions like so:

```csharp
public class Book : Entity, ICreatedOn, IModifiedOn
{
Expand All @@ -56,51 +63,66 @@ public class Book : Entity, ICreatedOn, IModifiedOn
public DateTime ModifiedOn { get; set; }
}
```

if your entity classes implements these interfaces, the library will automatically set the appropriate values so you can use them for sorting operations and other queries.

# The IEntity interface

if for whatever reason, you're unable to inherit the `Entity` base class, you can simply implement the `IEntity` interface to make your classes compatible with the library like so:

```csharp
public class Book : IEntity
{
[BsonId, ObjectId]
public string ID { get; set; }

public string GenerateNewID()
public string ID { get; set; } = null!;

public object GenerateNewID()
=> ObjectId.GenerateNewId().ToString();

public bool HasDefaultID()
=> string.IsNullOrEmpty(ID);
}
```

# Customizing the ID format
the default format of the IDs automatically generated for new entities is `ObjectId`. if you'd like to change the format of the ID, simply override the `GenerateNewID` method of the `Entity` class or implement the `IEntity` interface and place the logic for generating new IDs inside the `GenerateNewID` method.

if implementing `IEntity`, don't forget to decorate the ID property with the `[BsonId]` attribute.
the default format of the IDs automatically generated for new entities is `ObjectId`. if you'd like to change the type/format of the ID, simply override the `GenerateNewID` and `HasDefaultID` methods of the `Entity` base class or implement the `IEntity` interface. if implementing `IEntity`, don't forget to decorate the ID property with the `[BsonId]` attribute to indicate that it's the primary key.

```csharp
public class Book : IEntity
{
[BsonId]
public string ID { get; set; }
public Guid Id { get; set; } = Guid.Empty;

public string GenerateNewID()
=> $"{Guid.NewGuid()}-{DateTime.UtcNow.Ticks}";
public object GenerateNewID()
=> Guid.NewGuid();

public bool HasDefaultID()
=> Id == Guid.Empty;
}
```

> [!note]
> the type of the ID property cannot be changed to something other than `string`. PRs are welcome for removing this limitation.
> the type of the ID property can be whatever type you like (given that it can be serialized by the mongo driver). however, due to a technical constraint, only the following types are supported with the [referenced relationship](Relationships-Referenced.md) functionality:
>
> - string
> - long
> - ObjectId
<!-- <h2 style="color:#cb0000">A word of warning about custom IDs</h2> -->
> [!warning]
>it is highly recommended that you stick with `ObjectId` as it's highly unlikely it would generate duplicate IDs due to [the way it works](https://www.mongodb.com/blog/post/generating-globally-unique-identifiers-for-use-with-mongodb).
>
> it is highly recommended that you stick with `ObjectId` as it's highly unlikely it would generate duplicate IDs due to [the way it works](https://www.mongodb.com/blog/post/generating-globally-unique-identifiers-for-use-with-mongodb).
>
>
>if you choose something like `Guid`, there's a possibility for duplicates to be generated and data loss could occur when using the [partial entity saving](Entities-Save.md#save-entities-partially) operations. reason being, those operations use upserts under the hood and if a new entity is assigned the same ID as one that already exists in the database, the existing entity will get replaced by the new entity.
>
>
>
>the normal save operations do not have this issue because they use inserts under the hood and if you try to insert a new entity with a duplicate ID, a duplicate key exception would be thrown due to the unique index on the ID property.
>
>
>
>so you're better off sticking with `ObjectId` because the only way it could ever generate a duplicate ID is if more than 16 million entities are created at the exact moment on the exact computer with the exact same process.
# Create a collection explicitly

```csharp
await DB.CreateCollectionAsync<Book>(o =>
{
Expand All @@ -109,13 +131,15 @@ await DB.CreateCollectionAsync<Book>(o =>
o.MaxDocuments = 10000;
});
```
typically you don't need to create collections manually as they will be created automatically the first time you save an entity.

typically you don't need to create collections manually as they will be created automatically the first time you save an entity.
however, you'd have to create the collection like above if you need to use a custom *[COLLATION](https://docs.mongodb.com/manual/reference/collation/)*, create a *[CAPPED](https://docs.mongodb.com/manual/core/capped-collections/)*, or *[TIME SERIES](https://docs.mongodb.com/manual/core/timeseries-collections/)* collection before you can save any entities.

> [!note]
> if a collection already exists for the specified entity type, an exception will be thrown.
# Drop a collection

```csharp
await DB.DropCollectionAsync<Book>();
```
28 changes: 19 additions & 9 deletions Documentation/wiki/Relationships-Referenced.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Referenced Relationships

referenced relationships require a bit of special handling. a **one-to-one** relationship is defined using the `One<T>` class and **one-to-many** as well as **many-to-many** relationships are defined using the `Many<T>` class and you have to initialize the `Many<T>` child properties in the constructor of the parent entity as shown below.
referenced relationships require a bit of special handling. a **one-to-one** relationship is defined using the `One<T>` class and **one-to-many** as well as **many-to-many** relationships are defined using the `Many<TChild,TParent>` class and you have to initialize the `Many<TChild,TParent>` child properties in the constructor of the parent entity as shown below.

```csharp
public class Book : Entity
{
public One<Author> MainAuthor { get; set; }

public Many<Author> CoAuthors { get; set; }

[OwnerSide]
public Many<Genre> Genres { get; set; }
public Many<Author, Book> CoAuthors { get; set; }

[OwnerSide]
public Many<Genre, Book> Genres { get; set; }

public Book()
{
Expand All @@ -20,15 +20,16 @@ public class Book : Entity

public class Genre : Entity
{
[InverseSide]
public Many<Book> Books { get; set; }
[InverseSide]
public Many<Book, Genre> Books { get; set; }

public Genre()
{
this.InitManyToMany(() => Books, book => book.Genres);
}
}
```

notice the parameters of the `InitOneToMany` and `InitManyToMany` methods above. the first method only takes one parameter which is just a lambda pointing to the property you want to initialize.

the next method takes 2 parameters. first is the property to initialize. second is the property of the other side of the relationship.
Expand All @@ -48,10 +49,12 @@ await book.SaveAsync(); //call save on parent to store
```

### Reference removal

```csharp
book.MainAuthor = null;
await book.SaveAsync();
```

the original `author` in the `Authors` collection is unaffected.

### Entity deletion
Expand All @@ -73,10 +76,12 @@ await bookC.MainAuthor.ToEntityAsync() //returns null
```

## One-to-many & many-to-many

```csharp
await book.Authors.AddAsync(author); //one-to-many
await book.Genres.AddAsync(genre); //many-to-many
```

there's no need to call `book.SaveAsync()` again because references are automatically saved using special join collections. you can read more about them in the [Schema Changes](Schema-Changes.md#reference-collections) section.

however, do note that both the parent entity (book) and child (author/genre) being added has to have been previously saved so that they have their `ID` values populated. otherwise, you'd get an exception instructing you to save them both before calling `AddAsync()`.
Expand All @@ -92,6 +97,7 @@ there are other *[overloads](xref:MongoDB.Entities.Many`1#methods)* for adding r
> [click here](https://gist.github.com/dj-nitehawk/9971a57062f32fac8e7597a889d47714) to see a full example of a referenced one-to-many relationship.
### Reference removal

```csharp
await book.Authors.RemoveAsync(author);
await book.Genres.RemoveAsync(genre);
Expand All @@ -102,6 +108,7 @@ the original `author` in the `Authors` collection is unaffected. also the `genre
there are other *[overloads](xref:MongoDB.Entities.Many`1.RemoveAsync(`0,MongoDB.Driver.IClientSessionHandle,System.Threading.CancellationToken))* for removing relationships with multiple entities or just the string IDs.

### Entity deletion

when you delete an entity that's in a `one-to-many` or `many-to-many` relationship, all the references (join records) for the relationship in concern are automatically deleted from the join collections.

for example:
Expand Down Expand Up @@ -135,7 +142,9 @@ a reference can be turned back in to an entity with the `ToEntityAsync()` method
```csharp
var author = await book.MainAuthor.ToEntityAsync();
```

you can also project the properties you need instead of getting back the complete entity like so:

```csharp
var author = await book.MainAuthor
.ToEntityAsync(a => new Author
Expand All @@ -146,4 +155,5 @@ var author = await book.MainAuthor
```

# Transaction support
adding and removing related entities require passing in the session when used within a transaction. see [here](Transactions.md#relationship-manipulation) for an example.

adding and removing related entities require passing in the session when used within a transaction. see [here](Transactions.md#relationship-manipulation) for an example.
2 changes: 1 addition & 1 deletion Tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Medo.Uuid7" Version="1.8.1"/>
<PackageReference Include="Medo.Uuid7" Version="1.8.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1"/>
<PackageReference Include="MSTest.TestFramework" Version="3.1.1"/>
Expand Down
39 changes: 23 additions & 16 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
### NEW

- wip: ability to use any type for `ID` property and ability to name it based on mongodb conventions.
- todo: update docs about no support for relationships with custom id types except for `ObjectId` & `long`

### IMPROVEMENTS

- `Entity.ID` property has been made non-nullable
- support for dictionary based index keys #206
- various internal code refactors and optimizations
- upgrade mongodb driver to v2.22

### BREAKING CHANGES

- `Many<TParent>` is now `Many<TChild,TParent>`.
- `IEntity.HasDefaultID()` method must be implemented by entities if implementing `IEntity` directly.
### NEW

ability to use any type for primary key property and ability to name it based on mongodb conventions when implementing `IEntity` interface.

**NOTE:** due to a technical constraint, only the following primary key types are supported with referenced relationships.

- string
- long
- ObjectId

see #195 for more info.

### IMPROVEMENTS

- `Entity.ID` property has been made non-nullable #210
- support for dictionary based index keys #206
- upgrade mongodb driver to v2.22
- various internal code refactors and optimizations

### BREAKING CHANGES

- `Many<T>` is now `Many<TChild,TParent>` when defining referenced relationships. i.e. you now need to specify the type of the parent class that contains the property.
- `IEntity.GenerateNewID()` & `IEntity.HasDefaultID()` method must be implemented by entities if implementing `IEntity` directly.
Loading

0 comments on commit 7854a2f

Please sign in to comment.