ModificationHandler to build to Insert/Update/Delete commands
See original GitHub issueIs 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:
- Created 3 years ago
- Comments:5 (2 by maintainers)
Top 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 >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
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.Any news on the pull request?