question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Improve compiler support in Linq partial updates

See original GitHub issue

The Linq update builder currently accepts an anonymous record for partially updating a table. I think it is worth considering deprecating the anonymous record support (on the Linq builder only) in favor of a setColumn (or similarly named) operator that allows you to set individual columns.

Why? Better compiler support for partial updates with less chance of run-time exceptions!

  • setColumn can be constrained to 'T which will allow the F# compiler to provide type check errors at compile-time, whereas the anonymous record approach allows potential run-time errors.

For example:

update {
    for p in personTable do
    set {| FirstName = "UPDATED"; LastName = "UPDATED" |}
    where (p.Position = 1)
} 
|> conn.UpdateAsync

would become:

update {
    for p in personTable do
    setColumn p.FirstName "UPDATED" // constrained to only allow properties on `p`
    setColumn p.LastName "UPDATED"
    where (p.Position = 1)
} 
|> conn.UpdateAsync
  • A less important reason (but still a nice side effect) is that removing support for anonymous records it will greatly simplify the Linq update builder implementation by removing the extra 'U generic parameter.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:25 (25 by maintainers)

github_iconTop GitHub Comments

2reactions
JordanMarrcommented, Sep 10, 2021

I think I just imagined a way to implement multi column joins in the Linq API that might work… 🤞

1reaction
JordanMarrcommented, Sep 15, 2021

The multi-column join went really well! 🎉

    testTask "Inner Join Multi-Column" {
        let query = 
            select {
                for l in table<MultiJoinLeft> do
                innerJoin r in table<MultiJoinRight> on ((l.Key1, l.Key2) = (r.Key1, r.Key2)) 
                selectAll
            }

        Expect.equal query.Joins [
            InnerJoinOnMany ("MultiJoinRight", ["Key1", "MultiJoinLeft.Key1"; "Key2", "MultiJoinLeft.Key2"])
        ] ""
    }

    testTask "Left Join Multi-Column" {
        let query = 
            select {
                for l in table<MultiJoinLeft> do
                leftJoin r in table<MultiJoinRight> on ((l.Key1, l.Key2) = (r.Key1, r.Key2)) 
                selectAll
            }

        Expect.equal query.Joins [
            LeftJoinOnMany ("MultiJoinRight", ["Key1", "MultiJoinLeft.Key1"; "Key2", "MultiJoinLeft.Key2"])
        ] ""
    }

I had to temporarily butcher the test project by removing all the broken stuff, but I saw that you are working on the tests next, so I think I will just wait for you to complete the test rework, and then I’ll get a fresh pull of the fixed branch to apply the multi-join feature. That should keep things simple.

BTW, one workaround I implemented that you might consider to get the tests up and running quickly was to add a Legacy.fs file to the Tests project with the old where filter functions (since they were used all over the place to unit test the Linq queries):

/// Added temporarily to fix tests
module Dapper.FSharp.Legacy

/// Creates WHERE condition for column
let column name whereComp = Where.Column(name, whereComp)
/// WHERE column value equals to
let eq name (o:obj) = column name (Eq o)
/// WHERE column value not equals to
let ne name (o:obj) = column name (Ne o)
/// WHERE column value greater than
let gt name (o:obj) = column name (Gt o)
/// WHERE column value lower than
let lt name (o:obj) = column name (Lt o)
/// WHERE column value greater/equals than
let ge name (o:obj) = column name (Ge o)
/// WHERE column value lower/equals than
let le name (o:obj) = column name (Le o)
/// WHERE column like value
let like name (str:string) = column name (Like str)
/// WHERE column not like value
let notLike name (str:string) = column name (NotLike str)
/// WHERE column is IN values
let isIn name (os:obj list) = column name (In os)
/// WHERE column is NOT IN values
let isNotIn name (os:obj list) = column name (NotIn os)
/// WHERE column IS NULL
let isNullValue name = column name IsNull
/// WHERE column IS NOT NULL
let isNotNullValue name = column name IsNotNull
Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - Using a partial class property inside LINQ statement
So I modified LinqKit to pull out the get{} value when it encounters a property. The way it operates on the expression is...
Read more >
Adding Business Logic By Using Partial Methods - ADO.NET
In this article​​ The code that LINQ to SQL generates defines signatures as one part of a partial method. If you want to...
Read more >
LINQ to SQL (Part 4 - Updating our Database)
You can accomplish this by adding/removing data objects from the DataContext's table collections, and by then calling the SubmitChanges() method ...
Read more >
Learn all about Partial Class in C# | Simplilearn
Understand what is Partial Class in C#, Advantages of Partial Class, Points that you should be careful about partial classes with example.
Read more >
LINQKit is a free set of extensions for LINQ to SQL and ...
LINQKit is a free set of extensions for LINQ to SQL and Entity Framework power users. - GitHub - scottksmith95/LINQKit: LINQKit is a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found