Search code examples
mongodbmongodb-querymongodb-.net-driver

MongoDB C# Combining Fields



The Plan:
So now what I basically want is to take my propertys out of the class, let the user pick some and then pull a List with ONLY those propertys out of MongoDB.

The Code:
here is where the method starts:

private void DoStuffExecute(object obj)
        {
            Class class= new Class();
            ExtractClass(class);

            if (propList != null)
            {
                var result = classService.DoStuff(propList);
            }
        }

in "ExtractClass()" the Propertys are being pulled out of the Class.

void ExtractClass(object obj)
    {
        foreach (var item in obj.GetType().GetProperties())
        {
            propList.Add(item.Name);
        }
    }

and finally in "classService.DoStuff()" i try to set the "fields".

    public List<class> DoStuff(List<string> Props)
            {
                try
                {
                    var filter = Builders<class>.Filter.Empty;

                    var fields = Builders<class>.Projection.Include(x => x.ID);

                    foreach (var item in Props)
                    {
                        string str = "x.";
                        str += item.ToString();

                        fields = Builders<class>.Projection.Include(x => str);
                        fields = Builders<class>.Projection.Include(x => item);
                    }

                    var result = MongoConnectionHandler.MongoCollection.Find(filter).Project<class>(fields).ToList();

                return result;

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    var result = new List<class>();
                    return result;
                }
            }

when i run the programm it gives me an "Unable to determine the serialization information for x=> value"... since im giving it a string.

The Question: Does anyone have an Idea how to repair the code above or even make the plan work in another way?

thank you.


Solution

  • First of all: you are using such code lines as : var filter = Builders<class>.Filter.Empty; It is not possible, because class is a reserved keyword in c# (https://msdn.microsoft.com/en-us/library/x53a06bb.aspx) I assume, it's your Model, and i will speak about it as about Model class.

    Include Filter needs Expression as a parameter, not a string, you should construct is as a expression. That's the second thing. Third, you should combine your includes as a chain, So your part of creating Include Filter from string List should look like:

     var filter = Builders<Model>.Filter.Empty;
    
     var fields = Builders<Model>.Projection.Include(x => x.Id);
    
     foreach (var item in Props)
     {
           var par = Expression.Parameter(typeof(Model));
           var prop = Expression.Property(par, item);
           var cast = Expression.Convert(prop, typeof(object));
           var lambda = Expression.Lambda(cast, par);                                         
           fields =  fields.Include((Expression<Func<Model, object>>)lambda);              
     }
    

    I have all expresiions separate for better understanding: first you create Parameter (x=>), than you add property (x=>x.Property1), than you should cast it to object, and after all create Lambda Expression from it.

    And now the last part: You don't need all of it, Include function could get jsut a string as a parameter. So you could instead of all expression call write this:

    fields =  fields.Include(item);