[CSHARP-739] Linq needs support for private backing fields of public members Created: 06/May/13  Updated: 11/Mar/19  Resolved: 06/Apr/15

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.8.1
Fix Version/s: None

Type: Improvement Priority: Major - P3
Reporter: Craig Wilson Assignee: Unassigned
Resolution: Done Votes: 3
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Currently, it is impossible to have a readonly public member that is backed by a private member take part in LINQ queries. The below example illustrates as much:

namespace MongoBug
{
    using System.Collections.Generic;
    using System.Linq;
    using MongoDB.Bson;
    using MongoDB.Bson.Serialization;
    using MongoDB.Driver;
    using MongoDB.Driver.Linq;
    using NUnit.Framework;
 
    /// <summary>
    /// Test fixture showing issue with using LINQ queries against a backing field
    /// </summary>
    [TestFixture]
    public class LinqBugTestFixture
    {
        /// <summary>
        /// The connection string
        /// </summary>
        private const string ConnectionString = "mongodb://localhost:27017/mapping_private_field";
 
        /// <summary>
        /// Gets or sets the database.
        /// </summary>
        /// <value>
        /// The database.
        /// </value>
        private MongoDatabase Database { get; set; }
 
        /// <summary>
        /// Sets up the mapping for mongo.
        /// </summary>
        [TestFixtureSetUp]
        public void MapMongo()
        {
            var url = new MongoUrl(ConnectionString);
            var client = new MongoClient(url);
            this.Database = client.GetServer().GetDatabase(url.DatabaseName);
 
            this.Database.DropCollection("sampleModels");
 
            BsonClassMap.RegisterClassMap<SampleModel>(cm =>
            {
                cm.MapIdProperty(c => c.Id);
                cm.MapField("children").SetElementName("Children");
            });
        }
 
        /// <summary>
        /// Tests revealing the missing  mapping use case.
        /// </summary>
        [Test]
        public void TestShowMissingUseCase()
        {
            var model = new SampleModel();
            model.AddChild(new ChildrenModel { Name = "One" });
            model.AddChild(new ChildrenModel { Name = "Two" });
            model.AddChild(new ChildrenModel { Name = "Three" });
 
            var collection = this.Database.GetCollection<SampleModel>("sampleModels");
            collection.Save(model);
 
            var fromMongo = (from sample in collection.AsQueryable()
                             where sample.Children.Any(s => s.Name == "Two")
                             select sample).FirstOrDefault();
 
            Assert.AreEqual(model.Id, fromMongo.Id);
        }
 
        #region Model Class
        /// <summary>
        /// Sample Model that shows bug accessing private backing field through LINQ queries
        /// </summary>
        public class SampleModel
        {
            /// <summary>
            /// The backing field
            /// </summary>
            private IList<ChildrenModel> children;
 
            /// <summary>
            /// Initializes a new instance of the <see cref="SampleModel"/> class.
            /// </summary>
            public SampleModel()
            {
                this.children = new List<ChildrenModel>();
            }
 
            /// <summary>
            /// Gets or sets the id.
            /// </summary>
            /// <value>
            /// The id.
            /// </value>
            public ObjectId Id { get; set; }
 
            /// <summary>
            /// Gets the strings.
            /// </summary>
            /// <value>
            /// The strings.
            /// </value>
            public IEnumerable<ChildrenModel> Children
            {
                get { return this.children; }
            }
 
            /// <summary>
            /// Adds a child.
            /// </summary>
            /// <param name="toAdd">The child to add.</param>
            public void AddChild(ChildrenModel toAdd)
            {
                this.children.Add(toAdd);
            }
        }
 
        /// <summary>
        /// The child document
        /// </summary>
        public class ChildrenModel
        {
            /// <summary>
            /// Gets or sets the name.
            /// </summary>
            /// <value>
            /// The name.
            /// </value>
            public string Name { get; set; }
        }
        #endregion
    }
}


Generated at Wed Feb 07 21:37:41 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.