All Projects → DevZest → RDO.Net

DevZest / RDO.Net

Licence: MIT license
Relational Data Objects for .Net

Programming Languages

C#
18002 projects
Visual Basic .NET
514 projects

Projects that are alternatives of or similar to RDO.Net

jQuery-datatable-server-side-net-core
A simple Visual Studio solution using jQuery DataTable with Server-Side processing using .NET 5
Stars: ✭ 71 (+208.7%)
Mutual labels:  visual-studio, asp-net-core
Equinoxproject
Full ASP.NET Core 5 application with DDD, CQRS and Event Sourcing concepts
Stars: ✭ 5,120 (+22160.87%)
Mutual labels:  visual-studio, asp-net-core
AspNet-Core-REST-Service
VS2017/VS2019 project template for ASP.Net Core 3.1/5.0 to create fully functional production ready RESTful services
Stars: ✭ 57 (+147.83%)
Mutual labels:  visual-studio, asp-net-core
Darkui
Dark themed control and docking library for .NET WinForms.
Stars: ✭ 539 (+2243.48%)
Mutual labels:  visual-studio, windows-desktop
kontent-boilerplate-net
Kontent.ai Boilerplate for development of ASP.NET Core MVC applications.
Stars: ✭ 29 (+26.09%)
Mutual labels:  visual-studio, asp-net-core
ASPCore.Two-Factor-Authentication
Perform two factor authentication in an ASP.NET core application using Google Authenticator app
Stars: ✭ 29 (+26.09%)
Mutual labels:  visual-studio, asp-net-core
Professionalcsharp7
Code samples for the book Professional C# 7 and .NET Core 2.0 (with updates for 2.1), Wrox Press
Stars: ✭ 403 (+1652.17%)
Mutual labels:  visual-studio, asp-net-core
Sakura
SAKURA Editor (Japanese text editor for MS Windows)
Stars: ✭ 689 (+2895.65%)
Mutual labels:  visual-studio, windows-desktop
Dockpanelsuite
DockPanel Suite - The Visual Studio inspired docking library for .NET WinForms
Stars: ✭ 1,326 (+5665.22%)
Mutual labels:  visual-studio, windows-desktop
WebAPI2CLI
Execute ASP.NET Core WebAPI from Command Line
Stars: ✭ 28 (+21.74%)
Mutual labels:  visual-studio, asp-net-core
CleanArchitectureDemo
This is a demo project built on .NET Core 3.1 Clean Architecture. Please refer the articles mentioned in the readme to learn more.
Stars: ✭ 33 (+43.48%)
Mutual labels:  visual-studio, asp-net-core
Maple
Maple is a windows desktop application designed to support semi and non professional streamers in playing back local audio files and streaming content from the internet to their favorite playback device
Stars: ✭ 37 (+60.87%)
Mutual labels:  windows-desktop
VSGruvbox
A gruvbox UI theme for visual studio
Stars: ✭ 21 (-8.7%)
Mutual labels:  visual-studio
crynn
3D Game Engine Created In C++ & OpenGL
Stars: ✭ 45 (+95.65%)
Mutual labels:  visual-studio
EmbeddedBlazorContent
Library to load embedded content files (js and css) from Blazor libraries in server-side Blazor mode.
Stars: ✭ 39 (+69.57%)
Mutual labels:  asp-net-core
web-dashboard-demo
The following application contains the DevExpress Dashboard Component for Angular. The client side is hosted on the GitHub Pages and gets data from the server side that hosts on DevExpress.com.
Stars: ✭ 65 (+182.61%)
Mutual labels:  asp-net-core
PopMovies
Aplicativo em Android para organização dos seus filmes favoritos.
Stars: ✭ 41 (+78.26%)
Mutual labels:  mvp-architecture
QPrompt
Personal teleprompter software for all video creators. Built with ease of use, productivity, control accuracy, and smooth performance in mind.
Stars: ✭ 168 (+630.43%)
Mutual labels:  windows-desktop
forza-data-web
Forza Motorsport / Forza Horizon 4 Data-Out feature receiver web application
Stars: ✭ 18 (-21.74%)
Mutual labels:  asp-net-core
Voyager
Alternative routing system for aspnet api applications.
Stars: ✭ 44 (+91.3%)
Mutual labels:  asp-net-core

Welcome to RDO.Net

RDO.Net (Relational Data Objects for .Net) is an open source framework under MIT license to handle data in .Net platform, consists of the following libraries and tools:

image

Why RDO.Net

Enterprise application, typically backed by a relational database, has decades of history. Today's enterprise applications are unnecessarily complex and heavyweight, due to the following technical constraints:

  • Object-Relational Mapping (ORM, O/RM, and O/R mapping tool), as the core of enterprise applications, is still The Vietnam of Computer Science. Particularly, these difficulties are referred to as the object-relational impedance mismatch.
  • Data access testing, still stays on principles and guidelines. No widely practical use yet. Refactoring or changing an enterprise application is time consuming and error prone.
  • Existing data presentation solutions are far from ideal. Taking MVVM for example: it can be overkill for simple UI; in bigger cases, it can be hard to design the ViewModel up front in order to get the right amount of generality. Refactoring or changing data presentation code is time consuming and error prone.

The above challenges impose great burdens for developing and further changing an enterprise application. Many frameworks are trying to solve these problems however they are all far from ideal. RDO.Net is the only solution to these problems in an integral, not an after-thought way (strongly recommended reading through):

In the end, your application follows your business in a no-more-no-less basis - it adapts to your business, not vice versa:

  • Your application is 100% strongly typed from database to GUI, all in clean C#/VB.Net code. Refactoring or changing your code is much easier than ever before.
  • Your data access is best balanced for both programmability and performance. Rich set of data objects such as Model, Db, DbTable, DbQuery and DataSet are provided. No more object-relational impedance mismatch.
  • Data access testing is a first class citizen which can be performed easily. Data is the core of your application, now you can build much more robust data access layer.
  • A one-for-all, fully customizable data presenter is provided to handle presentation logic including layout, data binding and data validation, all consumed in clean C#/VB.Net code (no XAML needed). You don't need complex controls such as ListBox, TreeView, DataGrid any more. You data presentation code is greatly simplified because you can reuse all the presentation logic.
  • And much more with a lightweight runtime - you only need to add several dlls into your application, size ranged from tens to several hundereds KBs.

A Taste of RDO.Net

A fully featured sample application, AdventureWorksLT, together with others, is provided to demonstrate the use of RDO.Net:

image

The Model

using DevZest.Data;
using DevZest.Data.Annotations;
using DevZest.Data.SqlServer;

namespace DevZest.Samples.AdventureWorksLT
{
    [Computation(nameof(ComputeLineTotal))]
    [CheckConstraint(nameof(CK_SalesOrderDetail_OrderQty), typeof(UserMessages), 
     nameof(UserMessages.CK_SalesOrderDetail_OrderQty), 
     Description = "Check constraint [OrderQty] > (0)")]
    [CheckConstraint(nameof(CK_SalesOrderDetail_UnitPrice), 
     typeof(UserMessages), nameof(UserMessages.CK_SalesOrderDetail_UnitPrice), 
     Description = "Check constraint [UnitPrice] >= (0.00)")]
    [CheckConstraint(nameof(CK_SalesOrderDetail_UnitPriceDiscount), 
     typeof(UserMessages), nameof(UserMessages.CK_SalesOrderDetail_UnitPriceDiscount), 
     Description = "Check constraint [UnitPriceDiscount] >= (0.00)")]
    [DbIndex(nameof(IX_SalesOrderDetail_ProductID), Description = "Nonclustered index.")]
    public class SalesOrderDetail : BaseModel<SalesOrderDetail.PK>
    {
        [DbPrimaryKey("PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID", 
         Description = "Clustered index created by a primary key constraint.")]
        public sealed class PK : CandidateKey
        {
            public PK(_Int32 salesOrderID, _Int32 salesOrderDetailID)
                : base(salesOrderID, salesOrderDetailID)
            {
            }
        }

        public class Key : Key<PK>
        {
            static Key()
            {
                Register((Key _) => _.SalesOrderID, _SalesOrderID);
                Register((Key _) => _.SalesOrderDetailID, _SalesOrderDetailID);
            }

            protected override PK CreatePrimaryKey()
            {
                return new PK(SalesOrderID, SalesOrderDetailID);
            }

            public _Int32 SalesOrderID { get; private set; }

            public _Int32 SalesOrderDetailID { get; private set; }
        }

        public static readonly Mounter<_Int32> 
          _SalesOrderID = RegisterColumn((SalesOrderDetail _) => _.SalesOrderID);
        public static readonly Mounter<_Int32> 
          _SalesOrderDetailID = RegisterColumn((SalesOrderDetail _) => _.SalesOrderDetailID);
        public static readonly Mounter<_Int16> 
          _OrderQty = RegisterColumn((SalesOrderDetail _) => _.OrderQty);
        public static readonly Mounter<_Int32> 
          _ProductID = RegisterColumn((SalesOrderDetail _) => _.ProductID);
        public static readonly Mounter<_Decimal> 
          _UnitPrice = RegisterColumn((SalesOrderDetail _) => _.UnitPrice);
        public static readonly Mounter<_Decimal> 
         _UnitPriceDiscount = RegisterColumn((SalesOrderDetail _) => _.UnitPriceDiscount);
        public static readonly Mounter<_Decimal> 
         _LineTotal = RegisterColumn((SalesOrderDetail _) => _.LineTotal);

        public SalesOrderDetail()
        {
        }

        protected sealed override PK CreatePrimaryKey()
        {
            return new PK(SalesOrderID, SalesOrderDetailID);
        }

        private SalesOrderHeader.PK _fk_salesOrderHeader;
        public SalesOrderHeader.PK FK_SalesOrderHeader
        {
            get { return _fk_salesOrderHeader ?? 
                  (_fk_salesOrderHeader = new SalesOrderHeader.PK(SalesOrderID)); }
        }

        private Product.PK _fk_product;
        public Product.PK FK_Product
        {
            get { return _fk_product ?? (_fk_product = new Product.PK(ProductID)); }
        }

        [DbColumn(Description = "Primary key. Foreign key to SalesOrderHeader.SalesOrderID.")]
        public _Int32 SalesOrderID { get; private set; }

        [Identity]
        [DbColumn(Description = "Primary key. One incremental unique number per product sold.")]
        public _Int32 SalesOrderDetailID { get; private set; }

        [Required]
        [DbColumn(Description = "Quantity ordered per product.")]
        public _Int16 OrderQty { get; private set; }

        [Required]
        [DbColumn(Description = "Product sold to customer. Foreign key to Product.ProductID.")]
        public _Int32 ProductID { get; private set; }

        [Required]
        [SqlMoney]
        [DbColumn(Description = "Selling price of a single product.")]
        public _Decimal UnitPrice { get; private set; }

        [Required]
        [SqlMoney]
        [DefaultValue(typeof(decimal), "0", Name = "DF_SalesOrderDetail_UnitPriceDiscount")]
        [DbColumn(Description = "Discount amount.")]
        public _Decimal UnitPriceDiscount { get; private set; }

        [Required]
        [SqlMoney]
        [DbColumn(Description = "Per product subtotal. Computed as UnitPrice * (1 - UnitPriceDiscount) * OrderQty.")]
        public _Decimal LineTotal { get; private set; }

        [_Computation]
        private void ComputeLineTotal()
        {
            LineTotal.ComputedAs((UnitPrice * 
            (_Decimal.Const(1) - UnitPriceDiscount) * OrderQty).IfNull(_Decimal.Const(0)));
        }

        [_CheckConstraint]
        private _Boolean CK_SalesOrderDetail_OrderQty
        {
            get { return OrderQty > _Decimal.Const(0); }
        }

        [_CheckConstraint]
        private _Boolean CK_SalesOrderDetail_UnitPrice
        {
            get { return UnitPrice >= _Decimal.Const(0); }
        }

        [_CheckConstraint]
        private _Boolean CK_SalesOrderDetail_UnitPriceDiscount
        {
            get { return UnitPriceDiscount >= _Decimal.Const(0); }
        }

        [_DbIndex]
        private ColumnSort[] IX_SalesOrderDetail_ProductID => new ColumnSort[] { ProductID };
    }
}

The code of model can be manipulated in Model Visualizer tool window in Visual Studio:

image

The Database

using DevZest.Data;
using DevZest.Data.Annotations;
using DevZest.Data.SqlServer;
using System;
using System.Data.SqlClient;

namespace DevZest.Samples.AdventureWorksLT
{
    public partial class Db : SqlSession
    {
        public Db(string connectionString, Action<Db> initializer = null)
            : base(CreateSqlConnection(connectionString))
        {
            initializer?.Invoke(this);
        }

        private static SqlConnection CreateSqlConnection(string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString))
                throw new ArgumentNullException(nameof(connectionString));
            return new SqlConnection(connectionString);
        }

        public Db(SqlConnection sqlConnection)
            : base(sqlConnection)
        {
        }

        private DbTable<Address> _address;
        [DbTable("[SalesLT].[Address]", 
         Description = "Street address information for customers.")]
        public DbTable<Address> Address
        {
            get { return GetTable(ref _address); }
        }

        private DbTable<Customer> _customer;
        [DbTable("[SalesLT].[Customer]", Description = "Customer information.")]
        public DbTable<Customer> Customer
        {
            get { return GetTable(ref _customer); }
        }

        private DbTable<CustomerAddress> _customerAddress;
        [DbTable("[SalesLT].[CustomerAddress]", 
         Description = "Cross-reference table mapping customers to their address(es).")]
        [Relationship(nameof(FK_CustomerAddress_Customer_CustomerID), 
         Description = "Foreign key constraint referencing Customer.CustomerID.")]
        [Relationship(nameof(FK_CustomerAddress_Address_AddressID), 
         Description = "Foreign key constraint referencing Address.AddressID.")]
        public DbTable<CustomerAddress> CustomerAddress
        {
            get { return GetTable(ref _customerAddress); }
        }

        [_Relationship]
        private KeyMapping FK_CustomerAddress_Customer_CustomerID(CustomerAddress _)
        {
            return _.FK_Customer.Join(Customer._);
        }

        [_Relationship]
        private KeyMapping FK_CustomerAddress_Address_AddressID(CustomerAddress _)
        {
            return _.FK_Address.Join(Address._);
        }

        private DbTable<ProductCategory> _productCategory;
        [DbTable("[SalesLT].[ProductCategory]", 
         Description = "High-level product categorization.")]
        [Relationship(nameof
         (FK_ProductCategory_ProductCategory_ParentProductCategoryID_ProductCategoryID), 
         Description = "Foreign key constraint referencing ProductCategory.ProductCategoryID.")]
        public DbTable<ProductCategory> ProductCategory
        {
            get { return GetTable(ref _productCategory); }
        }

        [_Relationship]
        private KeyMapping 
        FK_ProductCategory_ProductCategory_ParentProductCategoryID_ProductCategoryID
        (ProductCategory _)
        {
            return _.FK_ParentProductCategory.Join(_);
        }

        private DbTable<ProductModel> _productModel;
        [DbTable("[SalesLT].[ProductModel]")]
        public DbTable<ProductModel> ProductModel
        {
            get { return GetTable(ref _productModel); }
        }

        private DbTable<ProductDescription> _productDescription;
        [DbTable("[SalesLT].[ProductDescription]", 
            Description = "Product descriptions in several languages.")]
        public DbTable<ProductDescription> ProductDescription
        {
            get { return GetTable(ref _productDescription); }
        }

        private DbTable<ProductModelProductDescription> _productModelProductDescription;
        [DbTable("[SalesLT].[ProductModelProductDescription]", 
            Description = "Cross-reference table mapping product descriptions and the language the description is written in.")]
        [Relationship(nameof(FK_ProductModelProductDescription_ProductModel_ProductModelID), 
           Description = "Foreign key constraint referencing ProductModel.ProductModelID.")]
        [Relationship(nameof
           (FK_ProductModelProductDescription_ProductDescription_ProductDescriptionID), 
           Description = "Foreign key constraint referencing ProductDescription.ProductDescriptionID.")]
        public DbTable<ProductModelProductDescription> ProductModelProductDescription
        {
            get { return GetTable(ref _productModelProductDescription); }
        }

        [_Relationship]
        private KeyMapping FK_ProductModelProductDescription_ProductModel_ProductModelID
                (ProductModelProductDescription _)
        {
            return _.FK_ProductModel.Join(ProductModel._);
        }

        [_Relationship]
        private KeyMapping 
          FK_ProductModelProductDescription_ProductDescription_ProductDescriptionID
          (ProductModelProductDescription _)
        {
            return _.FK_ProductDescription.Join(ProductDescription._);
        }

        private DbTable<Product> _product;
        [DbTable("[SalesLT].[Product]", Description = "Products sold or used in the manufacturing of sold products.")]
        [Relationship(nameof(FK_Product_ProductModel_ProductModelID))]
        [Relationship(nameof(FK_Product_ProductCategory_ProductCategoryID))]
        public DbTable<Product> Product
        {
            get { return GetTable(ref _product); }
        }

        [_Relationship]
        private KeyMapping FK_Product_ProductModel_ProductModelID(Product _)
        {
            return _.FK_ProductModel.Join(ProductModel._);
        }

        [_Relationship]
        private KeyMapping FK_Product_ProductCategory_ProductCategoryID(Product _)
        {
            return _.FK_ProductCategory.Join(ProductCategory._);
        }

        private DbTable<SalesOrderHeader> _salesOrderHeader;
        [DbTable("[SalesLT].[SalesOrderHeader]", 
         Description = "General sales order information.")]
        [Relationship(nameof(FK_SalesOrderHeader_Customer_CustomerID))]
        [Relationship(nameof(FK_SalesOrderHeader_Address_BillTo_AddressID))]
        [Relationship(nameof(FK_SalesOrderHeader_Address_ShipTo_AddressID))]
        public DbTable<SalesOrderHeader> SalesOrderHeader
        {
            get { return GetTable(ref _salesOrderHeader); }
        }

        [_Relationship]
        private KeyMapping FK_SalesOrderHeader_Customer_CustomerID(SalesOrderHeader _)
        {
            return _.FK_Customer.Join(Customer._);
        }

        [_Relationship]
        private KeyMapping FK_SalesOrderHeader_Address_BillTo_AddressID(SalesOrderHeader _)
        {
            return _.FK_BillToCustomerAddress.Join(CustomerAddress._);
        }

        [_Relationship]
        private KeyMapping FK_SalesOrderHeader_Address_ShipTo_AddressID(SalesOrderHeader _)
        {
            return _.FK_ShipToCustomerAddress.Join(CustomerAddress._);
        }

        private DbTable<SalesOrderDetail> _salesOrderDetail;
        [DbTable("[SalesLT].[SalesOrderDetail]", 
         Description = "Individual products associated with a specific sales order. See SalesOrderHeader.")]
        [Relationship(nameof(FK_SalesOrderDetail_SalesOrderHeader))]
        [Relationship(nameof(FK_SalesOrderDetail_Product))]
        public DbTable<SalesOrderDetail> SalesOrderDetail
        {
            get { return GetTable(ref _salesOrderDetail); }
        }

        [_Relationship]
        private KeyMapping FK_SalesOrderDetail_SalesOrderHeader(SalesOrderDetail _)
        {
            return _.FK_SalesOrderHeader.Join(SalesOrderHeader._);
        }

        [_Relationship]
        private KeyMapping FK_SalesOrderDetail_Product(SalesOrderDetail _)
        {
            return _.FK_Product.Join(Product._);
        }
    }
}

The code of database can be manipulated via Db Visualizer tool window in Visual Studio:

image

Data and Business Layer

private async Task EnsureConnectionOpenAsync(CancellationToken ct)
{
    if (Connection.State != ConnectionState.Open)
        await OpenConnectionAsync(ct);
}

public async Task<DataSet<SalesOrderInfo>> 
  GetSalesOrderInfoAsync(_Int32 salesOrderID, CancellationToken ct = default(CancellationToken))
{
    var result = CreateQuery((DbQueryBuilder builder, SalesOrderInfo _) =>
    {
        builder.From(SalesOrderHeader, out var o)
            .LeftJoin(Customer, o.FK_Customer, out var c)
            .LeftJoin(Address, o.FK_ShipToAddress, out var shipTo)
            .LeftJoin(Address, o.FK_BillToAddress, out var billTo)
            .AutoSelect()
            .AutoSelect(c, _.Customer)
            .AutoSelect(shipTo, _.ShipToAddress)
            .AutoSelect(billTo, _.BillToAddress)
            .Where(o.SalesOrderID == salesOrderID);
    });

    await result.CreateChildAsync(_ => _.SalesOrderDetails, 
                 (DbQueryBuilder builder, SalesOrderInfoDetail _) =>
    {
        builder.From(SalesOrderDetail, out var d)
            .LeftJoin(Product, d.FK_Product, out var p)
            .AutoSelect()
            .AutoSelect(p, _.Product)
            .OrderBy(d.SalesOrderDetailID);
    }, ct);

    return await result.ToDataSetAsync(ct);
}

public async Task<int?> CreateSalesOrderAsync(DataSet<SalesOrderInfo> salesOrders, 
                        CancellationToken ct)
{
    await EnsureConnectionOpenAsync(ct);
    using (var transaction = BeginTransaction())
    {
        salesOrders._.ResetRowIdentifiers();
        await SalesOrderHeader.InsertAsync(salesOrders, true, ct);
        var salesOrderDetails = salesOrders.GetChild(_ => _.SalesOrderDetails);
        salesOrderDetails._.ResetRowIdentifiers();
        await SalesOrderDetail.InsertAsync(salesOrderDetails, ct);

        await transaction.CommitAsync(ct);
        return salesOrders.Count > 0 ? salesOrders._.SalesOrderID[0] : null;
    }
}

public async Task UpdateSalesOrderAsync
       (DataSet<SalesOrderInfo> salesOrders, CancellationToken ct)
{
    await EnsureConnectionOpenAsync(ct);
    using (var transaction = BeginTransaction())
    {
        salesOrders._.ResetRowIdentifiers();
        await SalesOrderHeader.UpdateAsync(salesOrders, ct);
        await SalesOrderDetail.DeleteAsync
              (salesOrders, (s, _) => s.Match(_.FK_SalesOrderHeader), ct);
        var salesOrderDetails = salesOrders.GetChild(_ => _.SalesOrderDetails);
        salesOrderDetails._.ResetRowIdentifiers();
        await SalesOrderDetail.InsertAsync(salesOrderDetails, ct);

        await transaction.CommitAsync(ct);
    }
}

public Task<int> DeleteSalesOrderAsync(DataSet<SalesOrderHeader.Key> dataSet, 
                 CancellationToken ct)
{
    return SalesOrderHeader.DeleteAsync(dataSet, (s, _) => s.Match(_), ct);
}

Data Presentation

using DevZest.Data.Presenters;
using DevZest.Data.Views;
using DevZest.Data;
using System.Windows;
using System;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Diagnostics;

namespace DevZest.Samples.AdventureWorksLT
{
    partial class SalesOrderWindow
    {
        private class DetailPresenter : DataPresenter<SalesOrderInfoDetail>, 
                      ForeignKeyBox.ILookupService, DataView.IPasteAppendService
        {
            public DetailPresenter(Window ownerWindow)
            {
                _ownerWindow = ownerWindow;
            }

            private readonly Window _ownerWindow;

            protected override void BuildTemplate(TemplateBuilder builder)
            {
                var product = _.Product;
                builder.GridRows("Auto", "20")
                    .GridColumns("20", "*", "*", "Auto", "Auto", "Auto", "Auto")
                    .WithFrozenTop(1)
                    .GridLineX(new GridPoint(0, 2), 7)
                    .GridLineY(new GridPoint(2, 1), 1).GridLineY
                          (new GridPoint(3, 1), 1).GridLineY(new GridPoint(4, 1), 1)
                    .GridLineY(new GridPoint(5, 1), 1).GridLineY
                          (new GridPoint(6, 1), 1).GridLineY(new GridPoint(7, 1), 1)
                    .Layout(Orientation.Vertical)
                    .WithVirtualRowPlacement(VirtualRowPlacement.Tail)
                    .AllowDelete()
                    .AddBinding(0, 0, this.BindToGridHeader())
                    .AddBinding(1, 0, product.ProductNumber.BindToColumnHeader("Product No."))
                    .AddBinding(2, 0, product.Name.BindToColumnHeader("Product"))
                    .AddBinding(3, 0, _.UnitPrice.BindToColumnHeader("Unit Price"))
                    .AddBinding(4, 0, _.UnitPriceDiscount.BindToColumnHeader("Discount"))
                    .AddBinding(5, 0, _.OrderQty.BindToColumnHeader("Qty"))
                    .AddBinding(6, 0, _.LineTotal.BindToColumnHeader("Total"))
                    .AddBinding(0, 1, _.BindTo<RowHeader>())
                    .AddBinding(1, 1, _.FK_Product.BindToForeignKeyBox
                        (product, GetProductNumber).MergeIntoGridCell
                        (product.ProductNumber.BindToTextBlock()).WithSerializableColumns
                        (_.ProductID, product.ProductNumber))
                    .AddBinding(2, 1, 
                        product.Name.BindToTextBlock().AddToGridCell().WithSerializableColumns
                        (product.Name))
                    .AddBinding(3, 1, _.UnitPrice.BindToTextBox().MergeIntoGridCell())
                    .AddBinding(4, 1, _.UnitPriceDiscount.BindToTextBox
                        (new PercentageConverter()).MergeIntoGridCell
                        (_.UnitPriceDiscount.BindToTextBlock("{0:P}")))
                    .AddBinding(5, 1, _.OrderQty.BindToTextBox().MergeIntoGridCell())
                    .AddBinding(6, 1, _.LineTotal.BindToTextBlock
                        ("{0:C}").AddToGridCell().WithSerializableColumns(_.LineTotal));
            }
            ...
        }
    }
}

The above code will result in the following data grid UI:

image

Mock Database for Testing

public sealed class MockSalesOrder : DbMock<Db>
{
    public static Task<Db> CreateAsync(Db db, IProgress<DbInitProgress> progress = null, 
           CancellationToken ct = default(CancellationToken))
    {
        return new MockSalesOrder().MockAsync(db, progress, ct);
    }

    // This method is generated by a tool
    private static DataSet<SalesOrderHeader> Headers()
    {
        DataSet<SalesOrderHeader> result = DataSet<SalesOrderHeader>.Create().AddRows(4);
        SalesOrderHeader _ = result._;
        _.SuspendIdentity();
        _.SalesOrderID[0] = 1;
        _.SalesOrderID[1] = 2;
        ...
        _.ResumeIdentity();
        return result;
    }

    // This method is generated by a tool
    private static DataSet<SalesOrderDetail> Details()
    {
        DataSet<SalesOrderDetail> result = DataSet<SalesOrderDetail>.Create().AddRows(32);
        SalesOrderDetail _ = result._;
        _.SuspendIdentity();
        ...
        _.SalesOrderDetailID[0] = 1;
        _.SalesOrderDetailID[1] = 2;
        ...
        _.ResumeIdentity();
        return result;
    }

    protected override void Initialize()
    {
        // The order of mocking table does not matter, 
        // the dependencies will be sorted out automatically.
        Mock(Db.SalesOrderDetail, Details);
        Mock(Db.SalesOrderHeader, Headers);
    }
}

The code for testing data is generated from database:

image

Getting Started

It's highly recommended to start with our step by step tutorial.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].