{"id":13734575,"url":"https://github.com/TurnerSoftware/MongoFramework","last_synced_at":"2025-05-08T10:32:08.672Z","repository":{"id":39633989,"uuid":"78110067","full_name":"TurnerSoftware/MongoFramework","owner":"TurnerSoftware","description":"An \"Entity Framework\"-like interface for MongoDB","archived":false,"fork":false,"pushed_at":"2025-04-08T19:55:10.000Z","size":1047,"stargazers_count":394,"open_issues_count":51,"forks_count":35,"subscribers_count":23,"default_branch":"main","last_synced_at":"2025-04-08T20:36:33.890Z","etag":null,"topics":["entity-mapping","mongodb","orm"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TurnerSoftware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"Turnerj"}},"created_at":"2017-01-05T12:13:09.000Z","updated_at":"2025-04-05T17:08:19.000Z","dependencies_parsed_at":"2023-12-12T02:25:50.028Z","dependency_job_id":"6e39c55e-efec-4a0d-843f-0c83401da3e0","html_url":"https://github.com/TurnerSoftware/MongoFramework","commit_stats":{"total_commits":603,"total_committers":11,"mean_commits":54.81818181818182,"dds":0.3880597014925373,"last_synced_commit":"b7b881fef213191d7f497e43364453ef497840ca"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TurnerSoftware%2FMongoFramework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TurnerSoftware%2FMongoFramework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TurnerSoftware%2FMongoFramework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TurnerSoftware%2FMongoFramework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TurnerSoftware","download_url":"https://codeload.github.com/TurnerSoftware/MongoFramework/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253045846,"owners_count":21845783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["entity-mapping","mongodb","orm"],"created_at":"2024-08-03T03:00:57.570Z","updated_at":"2025-05-08T10:32:08.345Z","avatar_url":"https://github.com/TurnerSoftware.png","language":"C#","readme":"\u003cdiv align=\"center\"\u003e\n\n![Icon](images/icon.png)\n# MongoFramework\nAn \"Entity Framework\"-like interface for MongoDB\n\n![Build](https://img.shields.io/github/actions/workflow/status/TurnerSoftware/mongoframework/build.yml?branch=main)\n[![Codecov](https://img.shields.io/codecov/c/github/turnersoftware/mongoframework/main.svg)](https://codecov.io/gh/TurnerSoftware/MongoFramework)\n[![NuGet](https://img.shields.io/nuget/v/MongoFramework.svg)](https://www.nuget.org/packages/MongoFramework/)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/62fa31c90bf94f3d8e201b9684a7a4ca)](https://www.codacy.com/app/Turnerj/MongoFramework)\n\u003c/div\u003e\n\n## Overview\nMongoFramework tries to bring some of the nice features from Entity Framework into the world of MongoDB.\n\nSome of the major features include:\n- Entity mapping for collections, IDs and properties through attributes\n- Indexing through attributes (including text and geospatial)\n- Fluent mapping builder\n- Entity change tracking\n- Changeset support (allowing for queuing multiple DB updates to run at once)\n- Diff-updates (only _changes_ to an entity to be written)\n- Entity Buckets (clustering of small documents together, [improving index performance](https://www.mongodb.com/blog/post/building-with-patterns-the-bucket-pattern))\n- Runtime type discovery (serialize and deserialize without needing to specify every \"known\" type)\n\nMongoFramework is currently built on-top of the official MongoDB C# driver.\n\n## Licensing and Support\n\nMongoFramework is licensed under the MIT license. It is free to use in personal and commercial projects.\n\nThere are [support plans](https://turnersoftware.com.au/support-plans) available that cover all active [Turner Software OSS projects](https://github.com/TurnerSoftware).\nSupport plans provide private email support, expert usage advice for our projects, priority bug fixes and more.\nThese support plans help fund our OSS commitments to provide better software for everyone.\n\n## MongoFramework Extensions\nThese extensions are official packages that enhance the functionality of MongoFramework, integrating it with other systems and tools.\n\n### MongoFramework.Profiling.MiniProfiler\n[![NuGet](https://img.shields.io/nuget/v/MongoFramework.Profiling.MiniProfiler.svg)](https://www.nuget.org/packages/MongoFramework.Profiling.MiniProfiler/)\n[![NuGet](https://img.shields.io/nuget/dt/MongoFramework.Profiling.MiniProfiler.svg)](https://www.nuget.org/packages/MongoFramework.Profiling.MiniProfiler/)\n\nSupports profiling database reads and writes, pushing the data into [MiniProfiler](https://github.com/MiniProfiler/dotnet/).\n\n## Documentation\n\n### Entity Mapping Basics\nThe core mapping of entities and their properties is automatic however you have the choice of using the fluent mapping builder or certain attributes to alter this behaviour.\n\n**Fluent Mapping**\n```csharp\nusing MongoFramework;\n\npublic class MyEntity\n{\n  public string Id { get; set; }\n  public string Name { get; set; }\n  public string Description { get; set; }\n}\n\npublic class MyContext : MongoDbContext\n{\n  public MyContext(IMongoDbConnection connection) : base(connection) { }\n  public MongoDbSet\u003cMyEntity\u003e MyEntities { get; set; }\n\n  protected override void OnConfigureMapping(MappingBuilder mappingBuilder)\n  {\n    mappingBuilder.Entity\u003cMyEntity\u003e()\n      .HasProperty(m =\u003e m.Name, b =\u003e b.HasElementName(\"MappedName\"))\n      .ToCollection(\"MyCustomEntities\");\n  }\n}\n```\n\n**Attribute Mapping**\n```csharp\nusing MongoFramework;\nusing System.ComponentModel.DataAnnotations;\n\n[Table(\"MyCustomEntities\")]\npublic class MyEntity\n{\n  public string Id { get; set; }\n  [Column(\"MappedName\")]\n  public string Name { get; set; }\n  public string Description { get; set; }\n}\n\npublic class MyContext : MongoDbContext\n{\n  public MyContext(IMongoDbConnection connection) : base(connection) { }\n  public MongoDbSet\u003cMyEntity\u003e MyEntities { get; set; }\n}\n```\n\nFor attribute mapping, many of the core attributes are part of the `System.ComponentModel.Annotations` package.\n\n|Attribute|Description|\n|---------|-----------|\n|`[Table(\"MyFancyEntity\", Schema = \"MyNamespace\")]`|Map the Entity to the collection specified. When a schema is specified, it is prefixed onto the name with a \".\" (dot) separator.|\n|`[Key]`|Map the property as the \"Id\" for the entity. Only required if your key doesn't have a common name like \"Id\" etc.|\n|`[NotMapped]`|When applied to a class or property, skips mapping when reading/writing.|\n|`[Column(\"NewColumnName\")]`|Remaps the property with the specified name when reading/writing.|\n\n### Indexing\nMongoFramework supports indexing specified through both the fluent mapping builder and the `IndexAttribute`.\nThis is applied to the properties you want indexed and will apply the changes to the database when the context is saved.\n\n**Fluent Mapping**\n```csharp\nmappingBuilder.Entity\u003cIndexExample\u003e()\n  .HasIndex(e =\u003e e.EmailAddress, b =\u003e b.HasName(\"Email\").IsDescending(false));\n```\n\n**Attribute Mapping**\n```csharp\npublic class IndexExample\n{\n  public string Id { get; set; }\n\n  [Index(\"Email\", IndexSortOrder.Ascending)]\n  public string EmailAddress { get; set; }\n\n  public string Name { get; set; }\n}\n```\n\n\nThe following variations of indexes are supported across various property types:\n- [Single field](https://docs.mongodb.com/manual/core/index-single/)\n- [Compound](https://docs.mongodb.com/manual/core/index-compound/#compound-indexes)\n- [Multikey indexes](https://docs.mongodb.com/manual/core/index-multikey/)\n\nTo support compound indexes, define indexes with the same name across multiple properties.\nWhen doing this, you will want to control the order of the individual items in the compound index which is available through the `IndexPriority` property on the attribute. \n\nFor fluent mapping, you can specify multiple indexes in one declaration to combine them and handle nesting for complex data structures including through arrays.\n\n```csharp\npublic class TestModelBase\n{\n  public string Id { get; set; }\n  public string Name { get; set; }\n  public IEnumerable\u003cNestedModel\u003e ManyOfThem { get; set; }\n}\n\npublic class TestModel : TestModelBase\n{\n  public Dictionary\u003cstring, object\u003e ExtraElements { get; set; }\n  public string OtherName { get; set; }\n  public int SomethingIndexable { get; set; }\n  public NestedModelBase OneOfThem { get; set; }\n}\n\npublic class NestedModelBase\n{\n  public string Description { get; set; }\n}\n\nmappingBuilder.Entity\u003cTestModel\u003e()\n  .HasIndex(m =\u003e new\n  {\n    m.SomethingIndexable,\n    m.OneOfThem.Description,\n    m.ManyOfThem.First().AnotherThingIndexable\n  }, b =\u003e {\n    b.HasName(\"MyIndex\")\n      .IsDescending(true, false, false)\n  });\n```\n\n#### Special Index Types\nMongoFramework supports [Text](https://docs.mongodb.com/manual/core/index-text/) and [2dSphere](https://docs.mongodb.com/manual/core/2dsphere/) special indexes.\nFor attribute mapping, these special index types are selected through the `IndexType` property on the `IndexAttribute`.\n\nPlease consult MongoDB's documentation on when the indexes are appropriate and their restrictions.\n\n### Contexts and Connections\nLike Entity Framework, MongoFramework is built around contexts - specifically the `MongoDbContext`.\nAn example context would look like:\n\n```csharp\npublic class MyContext : MongoDbContext\n{\n  public MyContext(IMongoDbConnection connection) : base(connection) { }\n  public MongoDbSet\u003cMyEntity\u003e MyEntities { get; set; }\n  public MongoDbSet\u003cMyOtherEntity\u003e MyOtherEntities { get; set; }\n}\n```\n\nWhile it mostly feels the same as creating contexts in Entity Framework, there are a number of differences still with the biggest being in the creation of contexts.\nThe `IMongoDbConnection` is the core infrastructure that allows connection to MongoDB and is required to instantiate a context.\n\nYou can create an instance of a connection in two ways:\n```csharp\nIMongoDbConnection connection;\n\n//FromUrl\nconnection = MongoDbConnection.FromUrl(new MongoUrl(\"mongodb://localhost:27017/MyDatabase\")); //MongoUrl comes from the official MongoDB driver\n\n//FromConnectionString\nconnection = MongoDbConnection.FromConnectionString(\"mongodb://localhost:27017/MyDatabase\");\n```\n\n### Special Queries\nYou can perform text queries (with a Text index), geospatial distance queries (with a 2dSphere index) and geospatial intersecting queries.\n\n```csharp\nmyContext.MyDbSet.SearchText(\"text to search\");\nmyContext.MyDbSet.SearchGeoIntersecting(e =\u003e e.FieldWithCoordinates, yourGeoJsonPolygon);\nmyContext.MyDbSet.SearchGeoNear(e =\u003e e.FieldWithCoordinates, yourGeoJsonPoint);\n```\n\nEach of these returns an `IQueryable` which you can continue to narrow down the results like you would normally with LINQ.\nFor `SearchGeoNear` specifically, there are optional parameters for setting the distance result field, the minimum distance and the maximum distance.\n\n### Entity Buckets\nEntity buckets are a method of storing many smaller documents in fewer larger documents. MongoFramework provides various classes that help in creating and managing buckets.\nA typical setup for using an entity bucket might look like:\n\n```csharp\npublic class MyBucketGrouping\n{\n  public string SensorId { get; set; }\n  public DateTime Date { get; set; }\n}\n\npublic class MyBucketItem\n{\n  public DateTime EntryTime { get; set; }\n  public int Value { get; set; }\n}\n\npublic class MyContext : MongoDbContext\n{\n  public MyContext(IMongoDbConnection connection) : base(connection) { }\n  [BucketSetOptions(bucketSize: 1000, entityTimeProperty: nameof(MyBucketItem.EntryTime))]\n  public MongoDbBucketSet\u003cMyBucketGrouping, MyBucketItem\u003e MyBuckets { get; set; }\n}\n```\n\nThe attribute `BucketSetOptions` is required. \nThe `bucketSize` is the maximum number of items in a single bucket.\nThe `entityTimeProperty` identifies the property name in the sub-entity where a timestamp is stored.\n\nKeep in mind the limitations of MongoDB (size of document) when determining the number of items in a bucket.\n\nManaging buckets is very similar to managing normal entities though are currently limited to add data only.\n\n```csharp\nusing (var context = new MyContext(MongoDbConnection.FromConnectionString(\"mongodb://localhost:27017/MyDatabase\")))\n{\n  context.MyBuckets.AddRange(new MyBucketGrouping\n  {\n    SensorId = \"ABC123\",\n    Date = DateTime.Parse(\"2020-04-04\")\n  }, new []\n  {\n    new MyBucketItem\n    {\n      EntryTime = DateTime.Parse(\"2020-04-04T01:00\"),\n      Amount = 123\n    },\n    new MyBucketItem\n    {\n      EntryTime = DateTime.Parse(\"2020-04-04T02:00\"),\n      Amount = 456\n    },\n    new MyBucketItem\n    {\n      EntryTime = DateTime.Parse(\"2020-04-04T03:00\"),\n      Amount = 789\n    }\n  });\n\n  await context.SaveChangesAsync();\n}\n```\n\n### Extra Elements\nSometimes your model in the database will have more fields than the model you are deserializing to. You have two options to control the behaviour: ignore the fields or accept, mapping the extra fields to a specific dictionary.\n\nTo ignore the fields, you need to specify the `IgnoreExtraElements` attribute on the entity's class definition.\nTo map the fields, you need to specify the `ExtraElements` attribute on an `IDictionary\u003cstring, object\u003e` property.\n\n### Runtime Type Discovery\nMongoFramework provides runtime type discovery in two methods: automatically for any properties of type `object` and for any entities that specify the `RuntimeTypeDiscovery` attribute on their class definition.\n\nThis type discovery means that you don't need to know what potential types extend any others which you would otherwise need to set via the `BsonKnownTypes` attribute by the MongoDB driver.\n\n```csharp\n[RuntimeTypeDiscovery]\npublic class KnownBaseModel\n{\n}\n\npublic class UnknownChildModel : KnownBaseModel\n{\n}\n\npublic class UnknownGrandChildModel : UnknownChildModel\n{\n}\n```\n\nWithout the `RuntimeTypeDiscovery` attribute in this scenario, the model will fail to deserialize properly from the database.\n\n## Complete Example\n```csharp\nusing MongoFramework;\nusing System.ComponentModel.DataAnnotations;\n\npublic class MyEntity\n{\n  public string Id { get; set; }\n  public string Name { get; set; }\n  public string Description { get; set; }\n}\n\npublic class MyContext : MongoDbContext\n{\n  public MyContext(IMongoDbConnection connection) : base(connection) { }\n  public MongoDbSet\u003cMyEntity\u003e MyEntities { get; set; }\n}\n\n...\n\nvar connection = MongoDbConnection.FromConnectionString(\"YOUR_CONNECTION_STRING\");\nusing (var myContext = new MyContext(connection))\n{\n  var myEntity = myContext.MyEntities.Where(myEntity =\u003e myEntity.Name == \"MongoFramework\").FirstOrDefault();\n  myEntity.Description = \"An 'Entity Framework'-like interface for MongoDB\";\n  await myContext.SaveChangesAsync();\n}\n\n```\n","funding_links":["https://github.com/sponsors/Turnerj"],"categories":["Libraries","ORM","Audio"],"sub_categories":["MongoDb","GUI - other"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTurnerSoftware%2FMongoFramework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTurnerSoftware%2FMongoFramework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTurnerSoftware%2FMongoFramework/lists"}