Git Product home page Git Product logo

fsdl's Introduction

fsdl

NuGet

fsdl is a code generation library for creating Dapper-based C# persistence layer classes with backing SQL table definitions. It's not comprehensive by any means, but I've found it to be a real time saver during initial development of small, data-driven .NET projects.

fsdl works from entity specifications written in F#. You specify a set of database columns and the library generates CREATE SQL and a C# DTO class which maps to the table, all with the correct column sizes, nullable constraints, optional Dapper attributes etc.

Reference

You can specify most basic column data, constraint and index types. As the F# type syntax is so readable, I'll just directly paste the source code for now:

type DataType = INT | BIT | DATE | MONEY | TEXT | GUID | CHR of int | ENUM of Type

type Default = NONE | NULL | TRUE | FALSE | NOW | NEWGUID | VAL of int

type ColSpec =
    | Null of string * DataType
    | NotNull of string * DataType * Default
    | Identity of string * DataType * int * int

type ConstraintSpec =
    | PrimaryKey of string list
    | ForeignKey of string * string * string

type IndexSpec =
    | Clustered of string list
    | ClusteredUnique of string list
    | NonClustered of string list
    | NonClusteredUnique of string list

type PropertySetters = PublicSetters | PrivateSetters | NoSetters

type AccessModifier = Public | Private | Internal

See the example below for... well, an example.

Examples

Here's an example specification, along with the code it generates.

Specification

// Common columns for all tables and DTO classes (e.g. auditing data)
let baseColumns = [
    NotNull("Updated", DATE, NOW)
    NotNull("UserID", INT, VAL(1))
]

// As above, but for table constraints
let baseConstraints = [
    ForeignKey("UserID", "Users", "ID")
]

// Specification for the generated C# DTO classes
let dtoSpec = {
    ns = "fsdl.test"                    // Namespace for classes
    inheritFrom = Some "EntityBase"     // Classes can optionally inherit from a base class...
    interfaces = Some ["IDTO"]          // ... and optionally one or more interfaces
    accessModifier = Public             // Access modifier for the generated classes
    constructor = true                  // Classes can be generated with or without constructors
    setters = NoSetters                 // Generate public or private property setters (or omit them entirely)
    partial = true                      // Partial class generation
    dapperAttributes = true             // If true, DTOs are decorated with Dapper annotations
}

// Defines an entity, specifying table data types and constraints
let testEntity = {
    table = {
        name = "TestEntities"
        columns = [
            NotNull("ID", GUID, NEWGUID)
            Identity("IDX", INT, 1, 1)
            Null("Name", CHR(16))
            NotNull("Index", INT, VAL(100))
            NotNull("IsActive", BIT, FALSE)
            Null("TotalPrice", MONEY)
            Null("Description", TEXT)
            NotNull("FKID", INT, NONE)
            NotNull("EnumProp", ENUM(typeof<TestEnum>), VAL(int TestEnum.A))
        ] 
        constraints = [
            PrimaryKey(["ID"])
            ForeignKey("FKID", "FKEntities", "ID")
        ]
        indexes = [
            ClusteredUnique(["IDX"])
        ]
    }
    dto = { 
        name = "TestEntity"
        spec = dtoSpec 
    }
}

let entities = [testEntity]

// Generate the code and do whatever you like with it (save to files, concatenate etc)

generateDTOClassDefinitions entities baseColumns |> Console.Write |> ignore
generateTableDefinitions entities baseColumns |> Console.Write |> ignore
generateIndexDefinitions entities |> Console.Write |> ignore
generateConstraintDefinitions entities baseConstraints |> Console.Write |> ignore

Generated SQL

-- Create TestEntities
CREATE TABLE [TestEntities] (
    [ID] UNIQUEIDENTIFIER NOT NULL CONSTRAINT DF_TestEntities_ID DEFAULT NEWID(),
    [IDX] INT IDENTITY(1,1) NOT NULL,
    [Name] NVARCHAR(16) NULL,
    [Index] INT NOT NULL CONSTRAINT DF_TestEntities_Index DEFAULT 100,
    [IsActive] BIT NOT NULL CONSTRAINT DF_TestEntities_IsActive DEFAULT 0,
    [TotalPrice] DECIMAL(18,2) NULL,
    [Description] NVARCHAR(MAX) NULL,
    [FKID] INT NOT NULL,
    [EnumProp] INT NOT NULL CONSTRAINT DF_TestEntities_EnumProp DEFAULT 1,
    [Updated] DATETIME NOT NULL CONSTRAINT DF_TestEntities_Updated DEFAULT GETDATE(),
    [UserID] INT NOT NULL CONSTRAINT DF_TestEntities_UserID DEFAULT 1
)

GO

PRINT 'Tables Created'

-- Create TestEntities indexes

CREATE UNIQUE CLUSTERED INDEX IX_TestEntities_IDX ON [TestEntities] ([IDX])

GO

PRINT 'Indexes Created'

-- Create TestEntities constraints

ALTER TABLE [TestEntities] WITH CHECK ADD CONSTRAINT PK_TestEntities
PRIMARY KEY ([ID])

ALTER TABLE [TestEntities] WITH CHECK ADD CONSTRAINT FK_TestEntities_FKID_FKEntities_ID
FOREIGN KEY ([FKID]) REFERENCES [FKEntities] ([ID])

ALTER TABLE [TestEntities] WITH CHECK ADD CONSTRAINT FK_TestEntities_UserID_Users_ID
FOREIGN KEY ([UserID]) REFERENCES [Users] ([ID])

GO

PRINT 'Constraints Created'

Generated C#

using System;
using System.ComponentModel.DataAnnotations;
using d = Dapper.Contrib.Extensions;

namespace fsdl.test
{
    [d.Table("TestEntities")]
    public partial class TestEntity : EntityBase, IDTO
    {
        public TestEntity(
            Guid id,
            int idx,
            string name,
            int index,
            bool isActive,
            decimal? totalPrice,
            string description,
            int fkId,
            TestEnum enumProp,
            DateTime updated,
            int userId)
        {
            ID = id;
            IDX = idx;
            Name = name;
            Index = index;
            IsActive = isActive;
            TotalPrice = totalPrice;
            Description = description;
            FKID = fkId;
            EnumProp = enumProp;
            Updated = updated;
            UserID = userId;
        }

        [d.ExplicitKey]
        public Guid ID { get; }

        [d.Computed]
        public int IDX { get; }

        [StringLength(16)]
        public string Name { get; }

        public int Index { get; }

        public bool IsActive { get; }

        public decimal? TotalPrice { get; }

        public string Description { get; }

        public int FKID { get; }

        public TestEnum EnumProp { get; }
    }
}

If you use LINQPad (and if you don't, you should...), there is a test harness in this repository which allows you to play around and see what will be generated when you alter the specification.

fsdl's People

Contributors

markashleybell avatar

Stargazers

 avatar

Watchers

 avatar  avatar

fsdl's Issues

Support for Enums

Some int properties should be enums, so allow the specification of an enum type as an alternative.

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.