Coder Social home page Coder Social logo

dj-nitehawk / mongodb.entities Goto Github PK

View Code? Open in Web Editor NEW
526.0 21.0 68.0 12.6 MB

A data access library for MongoDB with an elegant api, LINQ support and built-in entity relationship management

Home Page: https://mongodb-entities.com

License: MIT License

C# 100.00% Batchfile 0.01%
mongodb mongodb-driver mongodb-repo csharp linq mongodb-orm net5 netstandard2

mongodb.entities's Introduction

license nuget nuget tests discord

MongoDB.Entities

A light-weight .net standard library with barely any overhead that aims to simplify access to mongodb by abstracting the official driver while adding useful features on top of it resulting in an elegant API surface which produces beautiful, human friendly data access code.

More Info:

please visit the official website for detailed documentation:

mongodb.entities's People

Contributors

cuongdo926 avatar dberry-rcs avatar dj-nitehawk avatar dolgsthrasir avatar fredimachado avatar maximys avatar molinch avatar paolobriones avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mongodb.entities's Issues

Override Save Async

We follow Domain Driven Design and hence most of our entities have domain events attached to them.

Generally these are fired when a entity is saved and MediatR orchestrates the sending of them to their relevant domain event handlers. Currently we have to implement an interface which forces an enitity to implement its own Save or SaveAsync Method which then calls the base Save or SaveAsyncFrom the Base Entity Class.

It would be intuitive if instead of implementing our own interface we can override the base implementation and add our own logic ontop of it

See an example below

public class Dog : Entity
{
    public string Colour { get; set; }  

    public string Name { get; set; }    

    public List<DomainEvents> { get; set; }  

    public override void Save()
    {
        //iterate over our domain events and dispatch here then save
         base.Save();
    }
}

I would be happy to create a PR for this and add it in should you be open to this.

ToDocument() should set ID to null

I want to copy an entity with ToDocument().
After that I save it to DB. The ObjectID is 000000000000000000000000.

Workaround:
Set the ID to null. I think this should be default.

image

Clarification on where to put repository-style methods

Being able to query the collection directly thru linq is pretty good, but i would also like to have pre-built methods that just return an entity list or a single entity based on parameters.

i.e.

public List<Book> GetBooksWith5StarReviews(){ ... }

Should this be put directly on the entity class?

Fluent mapping.

Hey. Great project! I would like to know, is it possible to map entities through fluent style? I want to use my models in shared library, so there any restriction on using inheritance in shared code.
Thanks in advance.

Two Contexts

Hello!

Is there a way to work with two contexts? One for reading and another for writing for example.

Loosen IEntity requirement

Would it be possible to loosen the IEntity requirement?
Maybe we could specify Id and ModifiedOn via attributes instead?
Also ModifiedOn could probably be optional?

It would allow having whatever name and structure for these, for example:

public class Book {
  [Id]
  public int Id { get; set; }
  public BookMetadata Metadata { get; set; }

  public class BookMetadata {
     [ModifiedOn]
     public DateTime ModifiedOn { get; set; }
  }
}

Btw is the ModifiedOn UTC based?

DB.GetInstance() should return null instead of throwing an exception

With the ability to create new instances of DB, instead of throwing an exception when the database is not yet initialized in the "instances" dictionary, shouldn't the API just return null so that the caller can initialize instead of using a try..catch to recover? Or maybe initialize automatically when calling DB.GetInstance()?

My use case is that my project has to support multiple MongoDB databases on different clusters; to simplify and centralize all my database operations, I created repository classes that automatically handle this.

Navigation property

First of all, thanks for your great work ๐Ÿ’•

I have a class with a navigation property (One-To-One).
This property can be null.

In the example project1 works fine, but project2 throws on the getter a NullReferenceException.
Why, and what is the right way :) ?

class Program
{
  static void Main(string[] args)
  {
    // todo: Init DB here

    Console.WriteLine("Create solution");
    var solution = new Solution();
    solution.Name = "solution";
    solution.Save();

    Console.WriteLine("Add children: project1...");
    Project project1 = new Project();
    project1.Name = "project1";
    project1.Solution = solution;
    project1.Save();
    solution.Projects.Add(project1);

    Console.WriteLine("Add children: project2 in folder...");
    SolutionFolder solutionFolder = new SolutionFolder();
    solutionFolder.Name = "solutionFolder";
    solutionFolder.Save();
    Project project2 = new Project();
    project2.Name = "project2";
    project2.Solution = null;
    project2.SolutionFolder = solutionFolder;
    project2.Save();
    solutionFolder.Projects.Add(project2);
    solutionFolder.Save();


    Solution test = db.Collection<Project>().AsQueryable().First(obj => obj.ID == project2.ID).Solution.ToEntity();
  }
}

public class Solution : Entity
{
  public string Name { get; set; }
  public Many<Project> Projects { get; set; }
  public ObservableCollection<SolutionFolder> SolutionFolders { get; set; }

  public Solution()
  {
    this.InitOneToMany(() => Projects);
    SolutionFolders = new ObservableCollection<SolutionFolder>();
  }
}

public class SolutionFolder : Entity
{
  public string Name { get; set; }
  public ObservableCollection<SolutionFolder> SolutionFolders { get; set; }
  public Many<Project> Projects { get; set; }
  public One<Solution> Solution { get; set; }

  public SolutionFolder()
  {
    this.InitOneToMany(() => Projects);
  }
}

public class Project : Entity
{
  public string Name { get; set; }
  public SolutionFolder SolutionFolder { get; set; }

  public One<Solution> Solution
  {
    get
    {
      if (_solution == null)
      {
        if (SolutionFolder?.Solution != null)
        {
          return SolutionFolder.Solution.ToEntity();
        }
      }
      return _solution;
    }
    set => _solution = value?.ToEntity();
  }

  private Solution _solution; // Also tried One<Solution>
}

Example isn't compiling

Hello,

I'm trying to use the Program.cs as a reference but it isn't compiling.

image

image

It says there is an ambiguous call.

Am I missing something?

Thank you!

Unable to connect remote connection string

The documentation just only shows the local environment setup.
Please provide a implementation of remote connection string with example.
Ex: mongodb+srv://:@bc-aymj0.gcp.mongodb.net/test_mongo

services.AddMongoDBEntities is very slow with atlas

Dear, i'm starting with MongoDB.Entities under an asp.net core 3.1 site, i added in startup.cs the service like this:
services.AddMongoDBEntities(
MongoClientSettings.FromConnectionString("mongodb+srv://xxxxx:xxxx-amkq1.mongodb.net/test?retryWrites=true&w=majority"),
"MyTEST");

My question is: Do you open the connection to DB when the service is added? Because the start is very very slow (over 8 seconds), is there something we can do to improve this? As the DB access is used only on some pages.

Note: i just start with MongoDB, your library seems very good with an easy access, good job ;)

Regards,
jc

Enable SCRAM-SHA-1 Login error

I had trouble logging in to mongo server and resolved it like this:

    string username = "user";
    string password = "password";
    string mongoDbAuthMechanism = "SCRAM-SHA-1";
    MongoInternalIdentity internalIdentity = new MongoInternalIdentity("admin", username);
    PasswordEvidence passwordEvidence = new PasswordEvidence(password);
    MongoCredential mongoCredential = new MongoCredential(mongoDbAuthMechanism, internalIdentity, passwordEvidence);

    new DB(new MongoClientSettings()
    {
         Server = new MongoServerAddress("localhost", 27017),
         Credential = mongoCredential
    }, "test");

    new DB("test", "localhost");

using with Azure functions

Hi,
I am trying to use this with Azure functions and use single instance of DB by doing :

private static Lazy lazyClient = new Lazy(InitializeDBfunction);
private static DB client => lazyClient.Value;

The problem is that above function is never called if i do Entity.Save().
Please recommend usage of this library with Azure functions.

Thanks

Support for MongoDB Clusters

Currently, we only specify a single server to connect to and the API needs to start supporting clustered MongoDB instances

DB.Delete<T>(x => x.Name == "") only deletes 1 record

Hey,

when you currently call DB.Delete(x => x.Name == "") with a predicate, it only deletes the first occurence found in the database.

Expected behaviour:
Delete all occurences with the specific predicate.

Btw.. calling DB.Collection().DeleteMany(x => x.Name == ""); works fine, just to point it out.

Many<T> entities don't show up on Mongo Atlas

Thanks for the excellent project. I'm using this with mongo atlas and tried out the example Program.cs

While everything is working great, objects being added using Many<T>.Add such as here are not showing up on the web dashboard. It IS being stored though because I can retrieve them.

Getting Exception at InitOneToMany

Hey, I have been getting random exceptions. Those don't always occur, but there are few in my log.

Version: 12.1.2

2020-06-12 04:52:55.2098||FATAL|30|   at System.Collections.Generic.HashSet`1.Contains(T item)
   at MongoDB.Entities.Many`1.SetupIndexes(IMongoCollection`1 collection)
   at MongoDB.Entities.Many`1.Init[TParent](TParent parent, String property)
   at MongoDB.Entities.Many`1..ctor(Object parent, String property)
   at MongoDB.Entities.Extensions.InitOneToMany[TChild](IEntity parent, Expression`1 propertyToInit)

Throws here

public SchoolPlanFileEntry()
{
   this.InitOneToMany(() => SchoolClasses);
}

Thanks for the help! :)

ChildrenQueryable 10 x slower than new Query

Hey,

when i'm doing

var isbnGroups = _isbnService.GetAllISBNGroups().ToList();

var list = new List<ISBNGroupModel>();
foreach (var group in isbnGroups)
{
    list.Add(new ISBNGroupModel()
    {
        BaseNumber = group.BaseNumber,
        Count = group.Count,
        AvailableCount = group.Numbers.ChildrenQueryable().Count()
    });
}
return Ok(list);

it takes about 700-900 ms, with 1 ISBN Group and 9999 ISBNs (Numbers)

when doing

var isbnGroups = _isbnService.GetAllISBNGroups().ToList();

var list = new List<ISBNGroupModel>();
foreach (var group in isbnGroups)
{
    var childrenCount = DB.Queryable<ISBN>().Count(x => x.ISBNGroup.ID == group.ID);
    list.Add(new ISBNGroupModel()
    {
        BaseNumber = group.BaseNumber,
        Count = group.Count,
        AvailableCount = childrenCount
    });
}
return Ok(list);

it takes about 48-172 ms..

Btw, is there a better way to count a Many Child Collection?

Sync over async - deadlock issue

Hello,

we are experiecing deadlock issues calling a synchronous metod (Execute()) of your library in our Web API application.
Checking the code, we found the sync method calls the async implementation (i.e. ExecuteAsync()) using the wrong pattern GetAwaiter().GetResult().

As workaround, we call the async method wrapping it into a Task.Run "statement", but we noticed other methods have the same issue (Save, ...).

We changed the method as follow and it works for us:

public List Execute()
{
return Task.Run(async () => await ExecuteAsync()).GetAwaiter().GetResult();
}

Can you check and fix all the sync over async implementation in order to avoid deadlock scenarios, please?

Regards

Is there a way to use geoWithin?

Hello!

I want to know if there is a way to work with Polygons and $geoWithin and $geoIntersects operators

I need to know if a person is in a determined city for example.

Thank you!

Blazor

HI,

Seem not compatible with Blazor (server). I try ASP.NET WEbApp and everything is fine but with Blazor can save but cannot do any Find()

Anything I am missing or it's just not ready for Blazor ?

How to get a count of modified documents via update

For example we have a code:

DB.Update<Profile>()
  .Match(a => a.Nick== nick && a.Money >= 10)
  .Modify(b => b.Inc(a => a.Money , -10))
  .Modify(b => b.CurrentDate(a => a.ModifiedOn))
  .Execute();

How can we understand was it applied or not? Can we get a count of modified documents?

PS. Thanks for the library.

Queryable does not return values with Activator.CreateInstance()

Hello,

I'm trying to use reflection to achieve some requirements and I cast my entity object to Entity after instantiating using reflection the Queryable method does not return any item.

Here it is my code

var entity = (MongoDB.Entities.Core.Entity)Activator.CreateInstance(entityType);
var tasks = entity.Queryable().ToList();

But if I run the Queryable method from the object like this its works well

var entity = new HttpRequestData();
var itens = d.Queryable().ToList();

Is there a way to do that?

Thanks in advance

Baseclass Entity.ModifiedOn should be settable

I have this interesting scenario where I'm trying to use Projection to select the return object via my API, I couldn't set the ModifiedOn value to null so this data always get sent to clients.

fulltext search again - case sensitive and insert on duplicate

i had a problem with fulltext search (textbox with keydown event and
search on all typed chars)

after long searching i found a solution,
but this is a slow version. on
DB.SearchText -< only case sensitve and the full word will search

my way:


//regex ? not work will result all:
             //var list = DB.Find<MyTestItem>()
             //    .MatchExpression("{ '$regex':'"+searchtext+"', '$options' : 'i'} " )                
             //    .Execute();

//work but is this the right way?
var list = DB.Queryable<MyTestItem>()
                       .Where(s =>
                              s.name.ToLower().Contains(searchtext) )                             
                       .ToList();

my question no2 ist why can i insert and handle a string only once in db?
how does the insert command look?

.Option(o => o.Unique = true)

or this, but i think its not perforant?

if (!DB.Find<MyTestItem>().Many(a => a.name == textBoxNameInsert.Text.Trim()).Exists(a => a.name == textBoxNameInsert.Text.Trim()))
            {
                var newItm = new MyTestItem()
                {
                    name = textBoxNameInsert.Text.Trim(),
                    vorname = textBoxNameInsert2.Text.Trim(),
                };
                newItm.Save();
                textBox1.AppendText("NEU angelget " + textBoxNameInsert.Text.Trim() + Environment.NewLine);
                loadListbox();
            }
            else
            {
                textBox1.AppendText("Schon vorhanden" + textBoxNameInsert.Text.Trim() + Environment.NewLine);
            }

Originally posted by @schorges in #21 (comment)

Support for saving files thru GridFS

Although uploading files to databases are frowned upon, there are instances where this is still needed.

For example, in your KiwilinkCRM system, I would imagine contract or service documents (pdf or any other format) must be available to users of the system for quick reference.

@dj-nitehawk Awesome work! New features are working really well!

help with one-To-many relationship

i have objet A that contain list of objet B
why when i get A , attr B contain JoinCollection { .... } not the real data that i created ?

Get raw query

Hello,

Is there a way to get access to the raw query that will be sent to MongoDB?
For example:

var update = _database.UpdateAndGet<Game>()
                .Match(g => g.ID == game.ID && g.GameType == game.GameType)
                .Modify(g => g.Inc(g => g.Version, 1));

Would give:

db.getCollection('Game').update({_id: '5efa36fe6c18de73c8e13bc9', GameType: 1},{ $inc: { 'Version': 1 } })

That would help a lot for troubleshooting

Multiple exclusions ?

I am trying to use Projection in Find query but I can only use 1 exclusion, I am unable to use .Include("SomeField1").Exclude("SomeField2") as mentioned in the wikipages. I am actually looking for this:

var UsersData = await DB.Find<Users>()
                                    .Project(Filter => Filter.Exclude(x => x.Field1).Exclude(x => x.Field2))
                                    .ExecuteAsync();

How to write concurrent integration tests with multiple databases?

Heya. I'm using XUnit and I'm trying to write integration tests using your library. The issue right now that I am having is, is that I have no control over which Database is being used when calling AddAsync on a Many collection. The relationship tables are created in a different database than the actual entities.

        [Fact]
        public async Task Must_Fail()
        {
            var dbNameWithRelationships = "db_name_with_relationships";
            var dbNameWithoutRelationships = "db_name_without_relationships";

            var dbWithout = new DB(dbNameWithoutRelationships);
            var dbWith = new DB(dbNameWithRelationships);

            var planToday = new SchoolPlanModel();
            await dbWith.SaveAsync(planToday);

            var school = new SchoolModel();
            await dbWith.SaveAsync(school);
            await school.Plans.AddAsync(planToday);
            planToday.School = school;
            await dbWith.SaveAsync(planToday);
        }

Results in:

grafik

Is there class mapping ?

Hi

I just wanted to ask if I can still use attributes for class mapping. For example,

If I want to defined the BSONRepresentation type to string/int or any, I would use:

[BsonRepresentation(BsonType.Double)]
public double MinimumDoubleValue { get; set; } = 0.00150000;

Does this library support representation attributes and others ? or do I not need to write them and the library will automatically use the datatype as described for the properties.

P.s. I just don't want int, double numbers to be inserted as strings in the DB.

Expose IMongoDatabase thru the DB object

I'm finally trying to integrate GridFS file handling through the API and need to get access to the underlying IMongoDatabase instance to create an IGridFSBucket object.

Since the API supports multiple DB instances and internally manages this list, maybe the fix is to make the DB.GetDB() method as public, what do you think?

Thanks again @dj-nitehawk

QOL For save

Consider this example:

var author = new Author { Name = "Eckhart Tolle" }
author.Save();
book.Author = author;
book.Save()

Wouldn't it be better to detect author is new and not persisted in the book.Save() without having to call author.Save()

I'm thinking the ObjectId has not been set for author so it should be fairly easy to detect.

Thoughts?

A problem with mapping relational entities with AutoMapper

I'm trying to map a relational property to a normal entity, however I can't figure out how to go on about this. I have an entity class and a DTO class, let's take Product for example.

Product.cs:
public One<Discount> Discount

ProductResponse.cs:
public Discount Discount

Now AutoMapper doesn't know how to map this because these two objects have different class types, so I want to configure every property with the type One to convert it using .toEntity().

So if Product were to be automapped by AutoMapper it would convert One to Discount using .toEntity(). Is there any way to achieve this?

DB.Initialize is not thread safe

If you have two or more databases, you can get an initialization issue because this part of DB.Initialize is called multiple times:

if (!isSetupDone)
            {
                BsonSerializer.RegisterSerializer(new DateSerializer());
                BsonSerializer.RegisterSerializer(new FuzzyStringSerializer());
                BsonSerializer.RegisterSerializer(typeof(decimal), new DecimalSerializer(BsonType.Decimal128));
                BsonSerializer.RegisterSerializer(typeof(decimal?), new NullableSerializer<decimal>(new DecimalSerializer(BsonType.Decimal128)));

                ConventionRegistry.Register(
                    "IgnoreExtraElements",
                    new ConventionPack { new IgnoreExtraElementsConvention(true) },
                    type => true);

                ConventionRegistry.Register(
                    "IgnoreManyProperties",
                    new ConventionPack { new IgnoreManyPropertiesConvention() },
                    type => true);

                isSetupDone = true;
            }

I think you should move this section out of here, remove the boolean isSetupDone, and instead place it in DB static constructor.

That's the exception that can happen:

Message: 
    MongoDB.Bson.BsonSerializationException : There is already a serializer registered for type Date.
  Stack Trace: 
    BsonSerializerRegistry.RegisterSerializer(Type type, IBsonSerializer serializer)
    BsonSerializer.RegisterSerializer(Type type, IBsonSerializer serializer)
    BsonSerializer.RegisterSerializer[T](IBsonSerializer`1 serializer)
    DB.Initialize(MongoClientSettings settings, String db)
    DB.ctor(MongoClientSettings settings, String database)

ChildrenCount is counting dead items

Hey, i just found a bug (i think its a bug).

If you add a relational item to a Many Collection and you go inside the database and delete it manually (without deleting the reference in the relation table which gets auto created), ChildrenCount will count the objects based on the relational table, it doesnt matter if the real document doesnt even exist anymore.

Greetings

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.