16 people following this project (follow)

Marr DataMapper provides a fast and easy to use wrapper around ADO.NET that enables you to focus more on your data access queries without having to write plumbing code.
Load one-to-one, one-to-many, and inherited entity models with ease. No special base class required.

Learn more: documentation

NuGet: https://nuget.org/packages/MarrDataMapper

Highlights

  • Lazy loaded relationships defined using expressive Linq syntax:
        public void CreateMappings()
        {
            MapBuilder builder = new MapBuilder();

            builder.BuildColumnsFromSimpleTypes<Order>()
                .For(b => b.ID).SetPrimaryKey();

            builder.Relationships<Order>()
                .For("_orderItems").LazyLoad((db, order) => 
                    db.Query<OrderItem>().Where(oi => oi.OrderID == order.ID).ToList());

            builder.BuildColumnsFromSimpleTypes<OrderItem>();
        }


  • Linq syntax for easy parameterized querying with ORM capabilities:
List<Person> people = db.Query<Person>().Where(p => p.Age >= 18);

  • Custom query builder makes it easy to dynamically append where conditions:
List<Person> people = db.Query<Person>()
                .Where(p => p.Name == "Bob" || p.Name == "Robert")
                .AndWhere("([Age] = 35)")
                .OrderBy(p => p.Name);

// Generates a query with the following where clause: 
"WHERE ([t0].[Name] = @P0 OR [t0].[Name] = @P1) AND ([Age] = 35)"

  • Convenient syntax for querying simple lists of primitive data types
List<string> names = db.Query<string>("SELECT FirstName + ' ' + LastName FROM PersonTbl");

  • Can easily access the DataReader directly if needed:
List<Person> people = db.ExecuteReader(
                "SELECT * FROM tblPerson",
                r => new Person { ID = r.GetInt32(0), Name = r.GetString(1) }
);

  • Can translate unnormalized query data (like a view) into a multilayered object graph by using the .Graph() method, or by using the QueryToGraph method:
List<Person> people = db.Query<Person>()
                .Graph()
                .Where(p => p.Age >= 18);


or
List<Person> people = db.QueryToGraph<Person>("SELECT * FROM Person WHERE Age >= 18");

  • Paging is supported for SQL Server 2005 and higher:
                int pageNumber = 1;
                int pageSize = 20;

                var results = db.Query<Company>()
                        .OrderBy(c => c.Name)
                        .Page(pageNumber, pageSize)
                        .ToList();

or using standard linq paging syntax
                int pageNumber = 1;
                int pageSize = 20;

                var results = db.Query<Company>()
                        .OrderBy(c => c.Name)
                        .Skip(pageNumber - 1)
                        .Take(pageSize)
                        .ToList();

  • Ability to get rowcount
                List<Message> messages = UoW.DB.Query<Message>()
                    .Where(m => m.ToUser == recipient)
                    .OrderByDescending(m => m.SentOn)
                    .Page(pageNumber, pageSize)
                    .ToList();

                int totalRecords = UoW.DB.Query<Message>()
                    .Where(m => m.ToUser == recipient)
                    .GetRowCount();

  • Testable Interface driven design
IDataMapper db = MockRepository.GenerateMock<IDataMapper>();

            var queryBuilder = MockRepository.GenerateMock<QueryBuilder<Product>>();
            var sortBuilder = MockRepository.GenerateMock<SortBuilder<Product>>();
            queryBuilder.Expect(b => b.Where("")).IgnoreArguments().Return(sortBuilder);
            sortBuilder.Expect(b => b.ToList()).Return(new List<Product> {
                new Product { ID = 18, Name = "Product18" },
                new Product { ID = 19, Name = "Product19" },
                new Product { ID = 20, Name = "Product20" }
            });
            

            db.Expect(d => d.Query<Product>()).Return(queryBuilder);

  • Fluent syntax for creating object / data mappings via code
        public void InitMappings()
        {
            MapBuilder builder = new MapBuilder();

            builder.BuildTable<Person>("PersonTable");

            builder.BuildColumns<Person>()
                .For(p => p.ID)
                    .SetPrimaryKey()
                    .SetReturnValue()
                    .SetAutoIncrement();

            builder.BuildRelationships<Person>();

            builder.BuildColumns<Pet>()
                .For(p => p.ID)
                    .SetPrimaryKey()
                    .SetAltName("Pet_ID")
                .For(p => p.Name)
                    .SetAltName("Pet_Name");
        }

  • Can also declare object / data mappings using attributes
[Table("PersonTable")]
public class Person
{
        [Column("First_Name"]
        public string FirstName { get; set; }

        [Column] // Uses property name by default
        public string Description { get; set; }
}

  • Easy instantiation of the DataMapper:
protected IDataMapper CreateDB()
{
    IDataMapper db = new DataMapper(
            System.Data.SqlClient.SqlClientFactory.Instance, 
            "[db connection string goes here]");

    db.SqlMode = SqlModes.Text;
    return db;
}

  • MDM uses a FastReflection library that uses caching in conjunction with reflection to provide very fast results
  • MDM can also work in medium trust environments (ie GoDaddy) using the optional "SimpleReflectionStrategy"

Learn more: documentation

Last edited Apr 20 at 12:59 AM by jmarr, version 39