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.

ModificationHandler to build to Insert/Update/Delete commands

See original GitHub issue

Is there any way to build an Insert/Update/Delete statement where you can optionally set which values to update/insert and then execute.

I’ve tried adapting an IModificationHandler interface suggested by @sdanyliv in an issue comment however I get the exception:

InvalidCastException: Unable to cast object of type 'LinqToDB.Linq.ValueInsertable`1[TestTable]' to type 'ValueInsertable`1[TestTable]'.

The Interfaces code is:

  public interface IModificationHandler {
    Type EntityType { get; }
  }

  public interface IModificationHandler<T> : IModificationHandler {
    IQueryable<T> Deletable { get; set; }
    IValueInsertable<T> Insertable { get; set; }
    IUpdatable<T> Updatable { get; set; }
  }

The Extensions code is:

  public static class _Extensions {

    public static IModificationHandler<T> SetValue<T, TV>(this IModificationHandler<T> modificationHandler, Expression<Func<T, TV>> field, TV value) {
      modificationHandler.Insertable = modificationHandler.Insertable.Value(field, value);
      modificationHandler.Updatable = modificationHandler.Updatable.Set(field, value);
      return modificationHandler;
    }

    public static IModificationHandler<T> SetValue<T, TV>(this IModificationHandler<T> modificationHandler, Expression<Func<T, TV>> field, Expression<Func<T, TV>> value) {
      modificationHandler.Updatable = modificationHandler.Updatable.Set(field, value);
      return modificationHandler;
    }

    public static IModificationHandler<T> SetValue<T, TV>(this IModificationHandler<T> modificationHandler, Expression<Func<T, TV>> field, Expression<Func<TV>> value) {
      modificationHandler.Insertable = modificationHandler.Insertable.Value(field, value);
      modificationHandler.Updatable = modificationHandler.Updatable.Set(field, value);
      return modificationHandler;
    }

    public static int Delete<T>(this IModificationHandler<T> modificationHandler) => modificationHandler.Deletable.Delete();
    public static int Insert<T>(this IModificationHandler<T> modificationHandler) => modificationHandler.Insertable.Insert();
    public static int Update<T>(this IModificationHandler<T> modificationHandler) => modificationHandler.Updatable.Update();

    public static Task<int> DeleteaAsync<T>(this IModificationHandler<T> modificationHandler, CancellationToken token = default) => modificationHandler.Deletable.DeleteAsync(token);
    public static Task<int> InsertAsync<T>(this IModificationHandler<T> modificationHandler, CancellationToken token = default) => modificationHandler.Insertable.InsertAsync(token);
    public static Task<int> UpdateAsync<T>(this IModificationHandler<T> modificationHandler, CancellationToken token = default) => modificationHandler.Updatable.UpdateAsync(token);

    public static IModificationHandler<T> GetModificationHandler<T>(this ITable<T> table, Expression<Func<T, bool>> wherePredicate) => new ModificationHandler<T>(table, wherePredicate);
    public static IModificationHandler<T> GetModificationHandler<T, TV>(this ITable<T> table, Expression<Func<T, bool>> wherePredicate, Expression<Func<T, TV>> field, TV value) => new ModificationHandler<T>(table, wherePredicate).SetValue(field, value);

  }

The Implementation code is:

  public class ModificationHandler<T> : IModificationHandler<T> {
    public Type EntityType => typeof(T);
    public IQueryable<T> Deletable { get;  set; }
    public IValueInsertable<T> Insertable { get;  set; }
    public IUpdatable<T> Updatable { get;  set; }

    public ModificationHandler(IQueryable<T> queryable, Expression<Func<T, bool>> wherePredicate) {
      Deletable = queryable.Where(wherePredicate);
      Insertable = new ValueInsertable<T>(queryable);
      Updatable = Deletable.AsUpdatable();
    }

    public ModificationHandler(ITable<T> table, Expression<Func<T, bool>> wherePredicate) : this(table.AsQueryable(), wherePredicate) { }

    [Obsolete("Try to remove: required to avoid cast exception")]
    public ModificationHandler() { }

    [Obsolete("Try to remove: required to avoid cast exception")]
    public static ModificationHandler<T> Init<T, TV>(ITable<T> table, Expression<Func<T, bool>> wherePredicate, Expression<Func<T, TV>> field, TV value)
      => new ModificationHandler<T> {
        Deletable = table.Where(wherePredicate),
        Insertable = table.Value(field, value),
        Updatable = table.Where(wherePredicate).Set(field, value)
      };

    [Obsolete("Try to remove: required to avoid cast exception")]
    public static ModificationHandler<T> Init<T, TV>(ITable<T> table, Expression<Func<T, bool>> wherePredicate, Expression<Func<T, TV>> field, Expression<Func<TV>> value)
      => new ModificationHandler<T> {
        Deletable = table.Where(wherePredicate),
        Insertable = table.Value(field, value),
        Updatable = table.Where(wherePredicate).Set(field, value)
      };

  }

The exception could be possibly be resolved if the ValueInsertable and Updatable classes were changed from internal to public in LinqExtensions.cs.

  public class SelectInsertable<T, TT> : ISelectInsertable<T, TT> {
    public SelectInsertable(IQueryable<T> query) {
      Query = query;
    }
    public IQueryable<T> Query;
  }

  public class Updatable<T> : IUpdatable<T> {
    public Updatable(IQueryable<T> query) {
      Query = query;
    }

    public IQueryable<T> Query;
  }

  public class ValueInsertable<T> : IValueInsertable<T> {
    public ValueInsertable(IQueryable<T> query) {
      Query = query;
    }

    public IQueryable<T> Query;
  }

Example Usage classes:

  public class TestDataConnection : DataConnection {
    public ITable<TestTable> TestTable => GetTable<TestTable>();
  }

  public class TestTable {
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime Created { get; set; } = DateTime.Now;
    public int CreatedById { get; set; }
    public DateTime LastModified { get; set; } = DateTime.Now;
    public int LastModifiedById { get; set; }
    public int ModifyCount { get; set; }
  }

Example usage:

  int? id = 1;
  var personId = 23;
  var name = "TestName";
  var doDelete = false;

  using(var dc = new TestDataConnection()) {
    var mh = dc.TestTable.GetModificationHandler(x => x.Id == id);
    if(doDelete) {
      // Perform Delete
      mh.Delete();
      // below could also be used:
      //    mh.Deletable.Delete();
    } else {
      // Set values common to both insert & update
      mh.SetValue(x => x.Name, name)
        .SetValue(x => x.LastModifiedById, personId);
      if(id > 0) {
        // Perform Update
        mh.SetValue(x => x.ModifyCount, x=> x.ModifyCount + 1)
          .SetValue(x => x.LastModified, DateTime.Now)
          .Update();
        // below could also be used:
        //   mh.Updatable.Update();
      } else {
        // Perform Insert
        mh.SetValue(x => x.CreatedById, personId)
          .Insert();
        // below could also be used:
        //   id = mh.Insertable.InsertWithInt32Identity();
      }
    }

  };

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
MaceWinducommented, May 1, 2023

Personally, I don’t think it belongs to linq2db directly, but we can add it to linq2db.Tools. Let’s see what other people think about it ( @linq2db ). Also we will need tests for it.

0reactions
tb-mtgcommented, May 1, 2023

Any news on the pull request?

Read more comments on GitHub >

github_iconTop Results From Across the Web

4. Inserting, Updating, Deleting - SQL Cookbook [Book]
Inserting, Updating, Deleting The past few chapters have focused on basic query ... The INSERT statement allows you to create new rows in...
Read more >
Data Manipulation: SELECT, INSERT, UPDATE, DELETE
If you are using FOR UPDATE on a table handler with page/row locks, the examined rows will be write-locked. JOIN syntax. MySQL supports...
Read more >
Insert, Update, Delete, and Select Operations on Tables ...
By using these operations, you can execute simple INSERT, UPDATE, SELECT, and DELETE statements qualified by a WHERE clause on the target ...
Read more >
How to: Update, Insert, and Delete Data with the ...
To let users modify data, you can enable update, insert, or delete operations on the LinqDataSource control. You can then connect the ...
Read more >
Performing Database Operations in Java | SQL CREATE ...
These basic operations are INSERT, SELECT, UPDATE and DELETE statements in SQL language. Although the target database system is Oracle ...
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