GithubHelp home page GithubHelp logo

efcore / efcore.fsharp Goto Github PK

View Code? Open in Web Editor NEW
227.0 227.0 25.0 2.21 MB

Adds F# design-time support to EF Core

License: MIT License

F# 97.55% Batchfile 0.02% Shell 0.15% Dockerfile 0.18% JavaScript 0.77% CSS 1.33%

efcore.fsharp's Introduction

EFCore.FSharp

Add F# design time support to EF Core.

For a basic introduction to running code-first migrations, please see the getting started guide.


Builds

Build Status

NuGet

Package Stable Prerelease
EFCore.FSharp NuGet Badge NuGet Badge

Usage

Install the package from NuGet and follow our Getting Started guide or our full documentation at https://efcore.github.io/EFCore.FSharp

Currently created migrations must be manually added to your solution in the correct order. Although migrations are created with sequential file names so a glob can also be used

<Compile Include="Migrations/*.fs" />

Building

> build.cmd <optional buildtarget> // on windows
$ ./build.sh  <optional buildtarget>// on unix

After building the solution, it will create a NuGet package in the dist folder. This can then be referenced as usual.

Developing

Make sure the following requirements are installed on your system:

or


Environment Variables

  • CONFIGURATION will set the configuration of the dotnet commands. If not set, it will default to Release.
    • CONFIGURATION=Debug ./build.sh will result in -c additions to commands such as in dotnet build -c Debug
  • GITHUB_TOKEN will be used to upload release notes and Nuget packages to GitHub.
    • Be sure to set this before releasing
  • DISABLE_COVERAGE Will disable running code coverage metrics. AltCover can have severe performance degradation so it's worth disabling when looking to do a quicker feedback loop.
    • DISABLE_COVERAGE=1 ./build.sh


Build Targets

  • Clean - Cleans artifact and temp directories.
  • DotnetRestore - Runs dotnet restore on the solution file.
  • DotnetBuild - Runs dotnet build on the solution file.
  • DotnetTest - Runs dotnet test on the solution file.
  • GenerateCoverageReport - Code coverage is run during DotnetTest and this generates a report via ReportGenerator.
  • WatchTests - Runs dotnet watch with the test projects. Useful for rapid feedback loops.
  • GenerateAssemblyInfo - Generates AssemblyInfo for libraries.
  • DotnetPack - Runs dotnet pack. This includes running Source Link.
  • SourceLinkTest - Runs a Source Link test tool to verify Source Links were properly generated.
  • PublishToNuGet - Publishes the NuGet packages generated in DotnetPack to NuGet via paket push.
  • GitRelease - Creates a commit message with the Release Notes and a git tag via the version in the Release Notes.
  • GitHubRelease - Publishes a GitHub Release with the Release Notes and any NuGet packages.
  • FormatCode - Runs Fantomas on the solution file.
  • BuildDocs - Generates Documentation from docsSrc and the XML Documentation Comments from your libraries in src.
  • WatchDocs - Generates documentation and starts a webserver locally. It will rebuild and hot reload if it detects any changes made to docsSrc files, libraries in src, or the docsTool itself.

efcore.fsharp's People

Contributors

bricelam avatar drk-mtr avatar dsshep avatar espenbrun avatar isaacabraham avatar jing8956 avatar kant2002 avatar literacyfanatic avatar lucasteles avatar mika76 avatar ninofloris avatar rstm-sf avatar simon-reynolds avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

efcore.fsharp's Issues

Foreign key constraints don't seem to be working

I have tried setting up a simple two way nav property between some tables.

All the tables are created and indexes are added to the foreign key columns, however no foreign key contraint is added.

I can see some stuff to do with foreign keys in the generated migration file, but it isn't getting applied to the database.

Reverse engineer support

We'll need to implement IScaffoldingCodeGenerator to support scaffolding a model from the database.

Use of byref in Migrations branch

This was brought to my attention in this thread: https://forums.fsharp.org/t/how-to-work-with-byref-and-pipe-operator/417/7

In the migrations branch, it appears there is usage of byref. Of that, there are 14 places where that usage is invalid; i.e., it produces code that may run, but is not necessarily going to run. These seem to all be of the following variety:

let foo (x: int byref) s =
    x <- x + 1
    printfn "%s %d" s x

let mutable x = 0

"hello" |> foo &x

This is explicitly disallowed, because |> is a generic function. It is not allowable to parameterize a type with a byref, i.e., foo<byref<Bar>>, yet this would occur if it were allowed.

So, there are two options here:

  1. Rewrite the 14 calls where a "hello" |> foo &x equivalent is made to foo &x "hello", which will not attempt to specialize |> to a byref<Foo>
  2. Use a ref cell.

Both are equally as invasive, though I would say that a ref cell is probably easier. For example, this:

    let private prependLine (addLineBreak: bool byref) (text:string) (sb:IndentedStringBuilder) =
        if addLineBreak then
            sb |> appendEmptyLine |> ignore
        else
            addLineBreak <- true

        sb |> append text |> ignore

    let appendLines (lines: string seq) skipFinalNewLine (sb:IndentedStringBuilder) =

        let mutable addLineBreak = false

        lines |> Seq.iter(fun l -> sb |> prependLine &addLineBreak l)

        if skipFinalNewLine then
            sb
        else
            sb |> appendEmptyLine

Becomes this:

    let private prependLine (addLineBreak: bool ref) (text:string) (sb:IndentedStringBuilder) =
        if addLineBreak.Value then
            sb |> appendEmptyLine |> ignore
        else
            addLineBreak := true

        sb |> append text |> ignore

    let appendLines (lines: string seq) skipFinalNewLine (sb:IndentedStringBuilder) =

        let addLineBreak = ref false

        lines |> Seq.iter(fun l -> sb |> prependLine addLineBreak l)

        if skipFinalNewLine then
            sb
        else
            sb |> appendEmptyLine

As far as I can tell, the other places this pattern is used could pass a reference cell instead, but a rewrite to not use pipelines with byrefs is also possible.

HasData seems to generate invalid code

A simple type:


[<CLIMutable>]
type Country = 
    {
        [<Key>]
        [<MaxLength(3)>]
        IsoCode: string
        EnglishName: String
        NativeName: String
    }

Given a list of values, I add them in DbContext:


        override _.OnModelCreating(builder: ModelBuilder): unit = 
            // Add all countries to the DB
            for country in CountryUtils.getAllCountries do
                builder.Entity<Country>().HasData(country) |> ignore

            base.OnModelCreating(builder)

The generated migrations code looks invalid:


        modelBuilder.Entity("Omnicv.Common.Db.Country", (fun b ->

            b.Property<string>("IsoCode")
                .HasMaxLength(3)
                .HasColumnType("TEXT") |> ignore
            b.Property<string>("EnglishName")
                .HasColumnType("TEXT") |> ignore
            b.Property<string>("NativeName")
                .HasColumnType("TEXT") |> ignore

            b.HasKey("IsoCode") |> ignore


            b.HasIndex("IsoCode")
                .IsUnique() |> ignore

            b.ToTable("Countries") |> ignore

            b.HasData([| 
                ({
                    ,
                    IsoCode = "abw"EnglishName = "Aruba"NativeName = "Aruba"} :> obj)
                 |> ignore
                ({
                    ,
                    IsoCode = "afg"EnglishName = "Afghanistan"NativeName = "Afghanistan"} :> obj)
                 |> ignore
                ({
                    ,
                    IsoCode = "ago"EnglishName = "Angola"NativeName = "Angola"} :> obj)
                 |> ignore
                ({
                    ,

Migrations support

We'll need to implement IMigrationsCodeGenerator to support adding a new migration.

Question: nullable foreign key

Trying to define a foreign key relationship as option causes the exception below. Is using option the right way to define nullable foreign key?

System.InvalidOperationException: The entity type 'FSharpOption<OmnicvUser>' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Sqlite.Internal.SqliteModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()

Can't create a migration

Created a basic EF context (blogs and posts). Trying to create a DB from it:

  1. Downloaded this repo.
  2. Ran build.cmd
  3. Referenced the generated nuget package from my application using paket.
  4. Installed the ef tool locally into my app.
  5. Run dotnet ef migrations add InitialCreate.
  6. Error: The project language 'F#' isn't supported by the built-in IMigrationsCodeGenerator service. You can try looking for an additional NuGet package which supports this language; moving your DbContext type to a C# class library referenced by this project; or manually implementing and registering the design-time service for programming language.

What am I doing wrong?

EF Core 5 support

Is your feature request related to a problem? Please describe.
Is support for EF Core 5 planned? Seems like some of the interfaces have changed.

Output of running against EF Core 5.0.3 project:

โ†’ dotnet ef migrations add Initial
Build started...
Build succeeded.
System.MissingMethodException: Method not found: 'System.String Microsoft.EntityFrameworkCore.Design.ICSharpHelper.Lambda(System.Collections.Generic.IReadOnlyList`1<System.String>)'.
   at EntityFrameworkCore.FSharp.EFCoreFSharpServices.Microsoft-EntityFrameworkCore-Design-IDesignTimeServices-ConfigureDesignTimeServices(IServiceCollection services)
   at DesignTimeServices.DesignTimeServices.Microsoft.EntityFrameworkCore.Design.IDesignTimeServices.ConfigureDesignTimeServices(IServiceCollection serviceCollection) in /home/tomiaijo/also/eol-pricing-tool/src/Server/DesignTimeServices.fs:line 13
   at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.ConfigureDesignTimeServices(Type designTimeServicesType, IServiceCollection services)
   at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.ConfigureUserServices(IServiceCollection services)
   at Microsoft.EntityFrameworkCore.Design.Internal.DesignTimeServicesBuilder.Build(DbContext context)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Method not found: 'System.String Microsoft.EntityFrameworkCore.Design.ICSharpHelper.Lambda(System.Collections.Generic.IReadOnlyList`1<System.String>)'.

migrationBuilder.AlterColumn miss argument construction

A migration was generated with the inconsistent code below:

migrationBuilder.AlterColumn<int>(
            name = "exchange_transaction_id"
            , table = "exchange_transactions1", nullable = false, oldType = "typedefof<int>", oldType = "Nullable(integer)", oldNullable = false)
            .OldAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) |> ignore

Notice there is two 'oldType' arguments. I searched in Microsoft docs and found this method signature. Than I found a similar argument called 'oldClrType' and changed oldType = "typedefof<int>" to oldClrType = typedefof<int> and the migration code could be executed.

I don't know why. It was pure intuition. I'm just reporting to let you know.

When scaffolding from database, string literal arrays are not generated

Describe the bug
A string literal array is generated as System.String[] not as the actual values, e.g. [| "A", "B" |].

To Reproduce
Scaffold from an existing database that will require a string literal array, e.g. enumeration.

Expected behavior
Array values generated correctly and able to be compiled.

Create a basic readme

Create a basic readme that explains:

  1. What this repository is for. What does it do, who should use it?
  2. A basic hello world for creating a migration from start to finish.

This would greatly assist people who come across this repository.

What needs to happen for a release on NuGet.

What are the things that still need to happen before this could be published to NuGet, and do you need any help with that? Would love to use this in projects in the future and if you could use it I would be happy to help out :)

Add support for many types per table relationships

These models were related types are all stored in one database table using a discrimator column would traditionally be modelled in C# using inheritance

They should be modelled as Discrimated Unions in F#

Example:

C#

public abstract class Person {}

public class Employee : Person {}

public class Manager : Person {}

F#

type Person =
| Employee of Employee
| Manager of Manager

Unable to access record fields via lambdas via EntityTypeBuilder

Describe the bug

Unable to access record fields via lambdas via EntityTypeBuilder - fails at run time during migration.

To Reproduce
Steps to reproduce the behavior:

Create a IEntityTypeConfiguration class for a record EF Core F# type.
Inside Configure(builder: EntityTypeBuilder try to access a property via lambda:
builder.Property(fun x -> x.FieldName)
Register this new IEntityTypeConfiguration in DbContext
Compile the projects (success)
Try to add a new migration

Observe the following exception:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.ArgumentException: The expression 'delegateArg0 => value(Omnicv.DataModule.CoreData+userIdColumn@45).Invoke(delegateArg0)' is not a valid member access expression. The expression should represent a
simple property or field access: 't => t.MyProperty'. (Parameter 'memberAccessExpression')
at Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions.GetInternalMemberAccess[TMemberInfo](LambdaExpression memberAccessExpression)
at Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions.GetMemberAccess(LambdaExpression memberAccessExpression)
at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder1.Property[TProperty](Expression1 propertyExpression)

Expected behavior
A new migration created successfully

Latest alpha generates invalid F# for migrations

Looks like the timestamped file from migrations has incorrect indentations, starting from the second table, and that causes to compilation errors, naturally.

First CreateTable is at column 9, but the second is at 13:

image

The next CreateTable is already at column 17 and so on. I could edit the file manually, but it would be better to fix the generator :)

Detailed project description

What does design time support means in terms of EF.Core?
Could you add some explanation, please?
What can I do with this package?
Create migrations and scaffold database?

Add unit tests

The project currently has poor unit test coverage and this has to be improved
Adding this ticket to track this work

Project doesn't build

On checking out master, doing a dotnet build gives the following errors:

error MSB4184: The expression "registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder" cannot be evaluated.
warning NU1503: Skipping restore for project 'C:\Users\Isaac\Source\Repos\EFCore.FSharp\EFCore.FSharp\EFCore.FSharp.fsproj'. The project file may be invalid or missing targets required for restore. [C:\Users\Isaac\Source\Repos\EFCore.FSharp\EFCore.FSharp.sln]
error MSB4184: The expression "registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder" cannot be evaluated.

Restore completed in 46.54 ms for C:\Users\Isaac\Source\Repos\EFCore.FSharp\EFCore.FSharp.Test\EFCore.FSharp.Test.fsproj.

error MSB4184: The expression "registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder" cannot be evaluated.
error MSB4184: The expression "registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder" cannot be evaluated.

How can I fix this?

.\build.cmd fails on Windows when FSharpMigrationsGeneratorTest.fs has Unix-style line endings

When you check-out the EFCore.FSharp code through Git, Git will by default convert the Unix-style line endings (LF) from the code in the repository to Windows-style line endings (CRLF).
This behaviour can be configured globally in Git (also per repository). See Github doc on configuring Git to handle line endings.

When you have Git configured to leave the line endings as-is โ€” or when you have downloaded the code as a .zip-file from the GitHub website and you have unzipped the .zip-file without converting line endings, as .zip-unpacking software tends not to doย โ€”
then .\build.cmd fails. The .nupkg file in the dist directory is not built.

Build log:

Build Time Report
---------------------------------------------------------------------
Target                   Duration
------                   --------
Clean                    00:00:00.0293730
DotnetRestore            00:00:11.4812587
DotnetBuild              00:00:24.2832148
DotnetTest               00:00:23.6683834   (Exception of type 'Fake.DotNet.MSBuildException' was thrown.)
GenerateCoverageReport   00:00:00           (skipped)
DotnetPack               00:00:00           (skipped)
Total:                   00:00:59.5815281
Status:                  Failure
---------------------------------------------------------------------
Script reported an error:
-> BuildFailedException: Target 'DotnetTest' failed.
-> One or more errors occurred. (Exception of type 'Fake.DotNet.MSBuildException' was thrown.)
-> MSBuildException: Exception of type 'Fake.DotNet.MSBuildException' was thrown.

In fact, it is the tests in FSharpMigrationsGeneratorTest.Migrations (tests\EFCore.FSharp.Tests\Migrations\Design\FSharpMigrationsGeneratorTest.fs) that fail.

The reason is that the tests contain multi-line strings describing what content generated files should have. The generated files are generated with native line endings; and the line endings in the expected value described by the multi-line strings are those of the FSharpMigrationsGeneratorTest.fs file.

Working workaround:
unix2dos tests\EFCore.FSharp.Tests\Migrations\Design\FSharpMigrationsGeneratorTest.fs before .\build.cmd
Even only changing the line endings in the multi-line strings to CRLF suffices.

Solutions:

  • Write a function that converts line endings in a string to native line endings. (I donโ€™t know whether such a function already exists somewhere.) And call that function on all multi-line strings describing the expected value;
  • or write a IgnoreLineEndingsDifferences string comparator. (I donโ€™t know whether such a string comparator already exists somewhere.) And use that string comparator to compare expected and actual file content in the tests.

Primary Key constraint is missing from all new migrations

Describe the bug
The constraints argument is missing in most if not all instances of generated migrationBuilder.CreateTable calls. Especially table.PrimaryKey types.

I believe #68 may be related to this. That deals with conventional detection of PK, but it seems to be all PK constraints are actually missing in the 5.0.3-alpha2 release, even those that are manually demarked with the [<Key>] annotation.

To Reproduce
Steps to reproduce the behavior:

  1. Create new table which includes a Primary Key annotated with [<Key>] in type definition
  2. Create new migration
  3. Observe the lack of a constraints argument in CreateTable call
  4. Perform database migration
  5. If successful, observe that no Primary Key is defined for database, and if Key was int type observe failure due to the inclusion of AUTO INCREMENT that is illegal in many databases engines outside of PK.

Expected behavior
Inclusion of a clause similar to that seen in older 3.1.12 release

//EntityFrameworkCore.FSharp version 3.1.12
override this.Up(migrationBuilder:MigrationBuilder) =
        migrationBuilder.CreateTable(
            name = "OrderNumbers"
            ,columns = (fun table -> 
            {
                ID = table.Column<int>(nullable = false)
                    .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn)
                OrderNumber = table.Column<string>(nullable = true, maxLength = Nullable(10))
                TSO = table.Column<bool>(nullable = false)
                Treated = table.Column<bool>(nullable = false)
                Items = table.Column<int>(nullable = false)
                PiecesReceived = table.Column<int>(nullable = false)
                PiecesTreated = table.Column<int>(nullable = false)
                PiecesUnReleased = table.Column<int>(nullable = false)
                Memo = table.Column<string>(nullable = true)
            })
            ,constraints =
                (fun table -> 
                    table.PrimaryKey("PK_OrderNumbers", (fun x -> (x.ID) :> obj)) |> ignore
                ) 
            ) |> ignore

Scaffolding from an existing database generates incorrect HasIndex calls

Describe the bug
Scaffold project from an existing database schema causes un-compilable HasIndex calls.

To Reproduce
Steps to reproduce the behavior:

  1. Scaffold from an existing database with indices, e.g. dotnet ef dbcontext scaffold <connection string> <ef provider>
  2. Generated code makes invalid calls to HasIndex(...):
entity
  .HasIndex(e.EntityId)

Expected behavior
Generated code should be:

entity
  .HasIndex("EntityId")

or

entity
  .HasIndex(fun e -> e.EntityId :> obj)

How do you use this?

How do you use this to generate migrations in an Fsharp project? I built the code (Edited global.json to use dotnet core 3.0) but I don't see an assembly in the resultant artifacts.

Optional properties requiring manual configuration when adding migration

An option type indicates nullability, it is not to be interpreted as an entity type by itself

System.InvalidOperationException: The entity type 'FSharpOption<string>' requires a primary key to be defined.
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
The entity type 'FSharpOption<string>' requires a primary key to be defined.

Automatically add generated files to fsproj

Both scaffolding and creating migrations results in new files being added to the project

Unlike C# the compilation order of F# is important so we will need to add them to the fsproj in the appropriate place within the project

Currently any generated files have to be added to the fsproj file manually

Add a CRUD example to Getting Started doc

First of all, thank you very much for this project.

Very useful.

I'm a newcomer in the F# world and I'm trying to use EF along with F# models. I could make trough every step in the Getting Started section successfully. But I do not have enough knowledge to put pieces together yet. So I would like to ask you to add a simple CRUD example with the created Post model in the Getting Started article.

Thank you.

Properties should be "required" by default, if not declared as option or nullable

I was under impression that by default fields like string, byte[] etc would be automatically flagged as IsRequired. However, a simple type like this:


    [<CLIMutable>]
    type CoreEventAttachment = 
    {
        Id: int64
        CoreEventInfoId: int64
        CoreEventInfo: CoreEventInfo
        CreatedAt: DateTime
        LastUpdatedAt: DateTime
        [<Required>]
        MimeType: string
        [<Required>]
        Attachment: byte[]
    }

Has Attachment and MimeType fields migration code without IsRequired - when no "Required" attribute is stamped, of course. Interestingly, all DateTime fields are flagged as IsRequired automatically.

I looked at the code, I can see that the decision to flag is made here, but I'm not entirely sure what the logic is exactly.

Type is a reserved word in F#

When generating migrations for sqlite, some columns have a "type" parameter. Since the function is called using named parameters, you end up with: table.Column<decimal>(nullable = false,type = "decimal(10, 0)", defaultValueSql = "('0')"). This generates a FS0010: Incomplete structured construct error, since type is a reserved keyword.

The only thing I can think of is just to call the function with all arguments. Per MSDN, "Note that for nullable parameters a null value means not-specified". However when I pass nulls for the arguments I didnt need, I get a "no overloads match" error. So I had to come up with values.

Column: member val SynsetId:decimal = 0.0m with get, set
Generated: table.Column<decimal>(nullable = false,type = "decimal(10, 0)", defaultValueSql = "('0')")
No overloads match: synset_id = table.Column<decimal>("decimal(10, 0)", null, null, false, "synset_id", false, null, null, null)
Compiles: table.Column<decimal>("decimal(10, 0)", Nullable(false), Nullable(10), false, "synset_id", false, "('0')", "('0')", "('0')")

Version 1.0 or 2.1?

Should this package start at version 1.0.0 or should the version somehow indicate that it's compatible with EF Core 2.1+

Scaffolded DbContext has unnecessary indentation

Describe the bug
Scaffolding from an existing database causes strange indentation:

open System
open System.Collections.Generic
open Microsoft.EntityFrameworkCore
open Microsoft.EntityFrameworkCore.Metadata
open EntityFrameworkCore.FSharp.Extensions

    open TestDbDomain

    type TestDbContext =
        inherit DbContext

        new() = { inherit DbContext() }
        new(options : DbContextOptions<TestDbContext>) =
            { inherit DbContext(options) }

        override this.OnConfiguring(optionsBuilder: DbContextOptionsBuilder) =
            if not optionsBuilder.IsConfigured then
                optionsBuilder.UseSqlServer("Initial Catalog=TestDatabase") |> ignore
                ()

        override this.OnModelCreating(modelBuilder: ModelBuilder) =
            base.OnModelCreating(modelBuilder)

            modelBuilder.RegisterOptionTypes()

To Reproduce
View the source code that is passing the test in FSharpDbContextGeneratorTest

Expected behavior
Code to look like:

open System
open System.Collections.Generic
open Microsoft.EntityFrameworkCore
open Microsoft.EntityFrameworkCore.Metadata
open EntityFrameworkCore.FSharp.Extensions

open TestDbDomain

type TestDbContext =
	inherit DbContext

	new() = { inherit DbContext() }
	new(options : DbContextOptions<TestDbContext>) =
		{ inherit DbContext(options) }

	override this.OnConfiguring(optionsBuilder: DbContextOptionsBuilder) =
		if not optionsBuilder.IsConfigured then
			optionsBuilder.UseSqlServer("Initial Catalog=TestDatabase") |> ignore
			()

	override this.OnModelCreating(modelBuilder: ModelBuilder) =
		base.OnModelCreating(modelBuilder)

		modelBuilder.RegisterOptionTypes()

Question: any practical differences between 2 types of declarations in DbContext?

Adding new types to DbContext, your intro suggests this type of syntax

    [<DefaultValue>] val mutable countries : DbSet<Country>
    member __.Countries with get() = __.countries and set v = __.countries <- v

Wouldn't it be the same to use this syntax from practical point of view?

    member val Countries: DbSet<Country> = null with get, set

As far as migrations generation, both seem to work fine...

System.InvalidOperationException: The entity type 'CustomAttributeData' requires a primary key to be defined

To Reproduce

I have a rather simple entity, defined in project A. I am trying to create migrations in project B, which has A as a reference. I am also trying use ASP.NET Identity with a custom user implementation, if that affects anything.

Entity:

[<CLIMutable>]
type Module = 
    {
        Id: int
        Name: string
        Version: string
        CreatedAt: DateTime
        LastUpdated: DateTime
    }

DbContext:

type ApplicationDbContext(options: DbContextOptions<ApplicationDbContext>) =
    inherit IdentityDbContext<OmnicvUser, IdentityRole<int>, int>(options)

    override _.OnConfiguring(options: DbContextOptionsBuilder) : unit =
        base.OnConfiguring(options)
        options
            .UseSqlite("Data Source=db.sqlite3") 
            |> ignore

    override _.OnModelCreating(builder: ModelBuilder): unit = 
        let types = [typedefof<Module>]

        let assemblies =
            types |> List.map (fun t -> Assembly.GetAssembly(t))
            |> List.distinct

        List.fold (fun (b: ModelBuilder) a -> b.ApplyConfigurationsFromAssembly(a)) builder assemblies
            |> ignore

        base.OnModelCreating(builder)

    [<DefaultValue>] val mutable modules : DbSet<Module>
    member __.Modules with get() = __.modules and set v = __.modules <- v

Seems quite straightforward. Id should be Module's key by convention, according to the docs. But when running migrations I get this exception:

System.InvalidOperationException: The entity type 'CustomAttributeData' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Sqlite.Internal.SqliteModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IModel model)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Expected behavior

I would expect the migration to succeed

Automatically add design-time services

Is your feature request related to a problem? Please describe.
Is there any way to avoid requiring users to manually add their own IDesignTimeServices implementation?

Describe the solution you'd like
The EFCore.VisualBasic project includes an MSBuild file in the nupkg that adds a source file to the project which enables dotnet ef to discover the design-time services automatically. Can this approach be replicated here?

Describe alternatives you've considered
None. This is the recommended pattern for design-time extensions.

Additional context
Available upon request. ๐Ÿ˜

Migrate from Travis CI to GitHub Actions

@bricelam

The Travis CI build is linked to bricelam/EFCore.FSharp, to restore build tests for it we can create a new build pointing to efcore/EFCore.FSharp but I don't have the necessary permissions to do that

Nullable needed on some column parameters

When creating a column, the unicode, maxLength, and fixedLength parameters need to be wrapped in Nullable(). I am generating migrations for sqlite.

Column: member val Gloss:string = "" with get, set
Example before: table.Column<string>(unicode = false)
after: table.Column<string>(unicode = Nullable(false))

`System` namespace not included in new migrations

Describe the bug
open System is not included in new migrations. This results in uses of Nullable, DateTime, and other common types to lack definition references and compilation to fail.

To Reproduce
Steps to reproduce the behavior:

  1. Create a new migration for database that has any instance of a non-required field anywhere (so that Nullable type will be included).
  2. Attempt to apply migration to database
  3. Observe failure due to uncompilable code generated in migration step

Expected behavior
open System should be included in any autogenerated file that requires the System namespace to compile.

Additional context
This bug affects version 5.0.3-alpha2

Exception with optional navigation properties

Attempting to register optional properties automatically (#24) results in the following error in the Northwind database

System.InvalidOperationException:
The relationship from 'Products.Category' to 'Categories.Products' with foreign key properties {'CategoryId' : FSharpOption<short>} cannot target the primary key {'CategoryId' : short} because it is not compatible.
Configure a principal key or a set of compatible foreign key properties for this relationship.

Optional navigation properties need to be supported, mapping from int option to int and TEntity option to TEntity will need to be added

Create the project

I'll set up the initial project to create the NuGet package and stub out the implementation.

Support for modelling Discriminated Unions

The F# Discriminated Union (DU) is a sum type where a type can contain a value of (e.g.) type A or B, but not both, for instance

type UserType =
| User
| Admin

The constituent types can be empty like above, or can have associated values, including plain types, complex types like records, or even other union types

type Person = {Id: int; First:string; Last:string}  // define a record type
type IntOrBool = I of int | B of bool

type MixedType =
  | Tup of int * int  // a tuple
  | P of Person       // use the record type defined above
  | L of int list     // a list of ints
  | U of IntOrBool    // use the union type defined above

EFCore.FSharp needs to be able to handle these types and

  • Generate valid migrations that can encode such a union
  • Be able to correctly identify cases where a database structure can be effectively modelled as a DU (#21 for example)
  • Existing tables with discriminator types should be mapped as a discriminated union.

Migrations

Each DU should be mapped to a table with a discriminator column and each associated type modelled aa linked entity in its own right. This approach will result in separate tables in the example above that model each field type

CREATE TABLE PersonId
(
    Id INT,
    First NVARCHAR,
    Last NVARCHAR
)

CREATE TABLE IntOrBool
(
    Id INT,
    Discriminator
    Int1 INT,
    Bool1 BIT
)

CREATE TABLE IntOrBool_Int
(
    Id INT,
    Int1 INT
)

CREATE TABLE IntOrBool_Bool
(
    Id INT,
    Bool1 BIT
)

CREATE TABLE MixedType
(
    Id INT,
    Discriminator NVARCHAR
)

CREATE TABLE MixedType_Tup
(
    Id INT PRIMARY KEY,
    MixedTypeId INT FOREIGN KEY, -- UNIQUE
    Int1 INT,
    Int2 INT
)

CREATE TABLE MixedType_P
(
    Id INT PRIMARY KEY,
    MixedTypeId INT FOREIGN KEY,
    PersonId INT FOREIGN KEY
)

CREATE TABLE MixedType_L
(
    Id INT PRIMARY KEY,
    MixedTypeId INT FOREIGN KEY, -- Duplicates allowed as it models a list
    Int1 INT
)

CREATE TABLE MixedType_U
(
    Id INT PRIMARY KEY,
    MixedTypeId INT FOREIGN KEY,
    IntOrBool INT FOREIGN KEY
)

This results in a lot of tables being generated but is I believe the most flexible system allowing for further expansion of the domain in future, for instance, if a new property was added to Person, or a new entry included in MixedType.Tup
It also allows the union type to be extended easily, just adding a new table instead of adding additional columns to existing tables

Scaffolding

We will need to be able to support scaffolding code from existing tables that would also include types such multiple types per table

Example from #21:

Where a many-types-per-table relationship from a Table Person with Discrimator values of Employee and Manager would be modelled in C# as

public abstract class Person
{
    public int Id {get; set;}
    public string First {get; set;}
    public string Last {get; set;}
}

public class Employee : Person
{
    public string JobTitle {get; set;}
}

public class Manager : Person
{
    public string Department {get; set;}
}

we should model it as

type Employee = { Id:int; First:string; Last:string; JobTitle:string }
type Manager = { Id:int; First:string; Last:string; Department:string }

type Person =
| Employee of Employee
| Manager of Manager

A potential issue here will be mapping columns to multiple types

Module opening is not generated for an entities for migrations

Describe the bug
Module opening is not generated for an entities for migrations

To Reproduce
Steps to reproduce the behavior:

  1. dotnet new -i "giraffe-template::*"
  2. dotnet new giraffe -o smthProject
  3. https://github.com/efcore/EFCore.FSharp/blob/master/GETTING_STARTED.md#add-design-time-services-interface-to-our-codebase
  4. ...
<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
        <AssemblyName>Giraffe.App</AssemblyName>
        <EnableDefaultContentItems>false</EnableDefaultContentItems>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="EntityFrameworkCore.FSharp" Version="5.0.3-alpha9" />
        <PackageReference Include="Giraffe" Version="5.0.0-rc-6" />
        <PackageReference Include="Giraffe.ViewEngine" Version="1.3.*" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.5" />
        <PackageReference Include="Ply" Version="0.3.*" />
    </ItemGroup>

    <ItemGroup>
        <Compile Include="DesignTimeServices.fs" />
        <Compile Include="Entities.fs" />
        <Compile Include="BloggingContext.fs" />
        <Compile Include="Migrations\20210507180335_Initial.fs" />
        <Compile Include="Migrations\BloggingContextModelSnapshot.fs" />
        <Compile Include="Program.fs" />
    </ItemGroup>

    <ItemGroup>
        <None Include="web.config" CopyToOutputDirectory="PreserveNewest" />
        <Content Include="WebRoot\**\*">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
    </ItemGroup>
</Project>
module Giraffe.Entities

open System.ComponentModel.DataAnnotations
open Microsoft.AspNetCore.Identity

[<AllowNullLiteral>]
type StoreUser() =
    inherit IdentityUser()
    member val FirstName = "" with get, set
    member val LastName = "" with get, set

type [<CLIMutable>] Order =
    {
        [<Key>] Id : int
        OrderNumber : string
        [<DefaultValue>] User : StoreUser
    }
module Giraffe.BloggingContext

open Giraffe.Entities
open Microsoft.EntityFrameworkCore

type BloggingContext () =
    inherit DbContext()

    member _.Orders : DbSet<Order> = Unchecked.defaultof<DbSet<Order>>

    override _.OnConfiguring (options: DbContextOptionsBuilder) =
        options.UseSqlite("Data Source=blogging.db") |> ignore

    override _.OnModelCreating (modelBuilder : ModelBuilder) =
        base.OnModelCreating(modelBuilder)

        modelBuilder
            .Entity<Order>()
            .HasData({
                Id = 1
                OrderNumber = "12345" })
            |> ignore

Expected behavior
dotnet ef database update will execute successfully

Screenshots
image

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.