In case you are using Microsoft SQL Server, you may have tried writing a
MERGE (...)
statement…. did you think it was fun? π
I think MERGE
statements are not fun at all, but from time to time it IS necessary to execute a performant UPSERT-type of operation.
Maybe you also know that the fastest way to execute a huge number of upserts is to
MERGE
statement, using the data type as its input typewhich can be pretty tedious to code.
Which is why the “upsert helper”, Debaser, was made π
With Debaser, you can execute obscenely fast upserts by doing the following things:
E.g. something like
class SomeDataRow { public SomeDataRow(int id, decimal number, string text) { Id = id; Number = number; Text = text; } public int Id { get; } public decimal Number { get; } public string Text { get; } }
will do.
This can be done like this:
var helper = new UpsertHelper<SomeDataRow>(connectionString);
and then you might want to
helper.CreateSchema();
when your application starts up. This will create a table, a custom table data type, and an appropriate stored procedure.
Pass very very long sequences of row objects to the upsert helper like this:
await helper.Upsert(longLongSequence);
which is cool, because the upsert helper streams the data to SQL Server.
If you think this looks cool, you should go to the Debaser wiki and read more about it, and maybe you want to Install-Package Debaser
and start punishing your database right away?
Happy upserting!
Happy New Year!
This is just to let you know that Rebus 3 is out π
The version was bumped to 3 because IAdvancedApi
and IDataBus
have been extended with more methods, and there are some changes around how to manually create transactions when sending messages outside of message handlers.
It is absolutely 100% wire-compatible with Rebus 2!
If you are interested in checking out which features were added, you can go to the tag comment and see the relevant bullets from the changelog. Most notable hightlights are a synchronous bus API (which can be accessed via bus.Advanced.SyncBus
) and a few extra much needed methods on IDataBus
.
DefaultTransactionContext
If you do this in your application:
using(var context = new DefaultTransactionContext())
{
AmbientTransactionContext.Current = context;
try
{
await bus.Publish(anEvent);
await context.Complete();
}
finally
{
AmbientTransactionContext.Current = null
}
}
you will have to change it to something like this:
using(var scope = new DefaultTransactionContextScope())
{
await bus.Publish(anEvent);
await scope.Complete();
}
which is much prettier and much much harder to mess up π
IDataBus
or IAdvancedApi
……you will have to add two extra methods on IDataBus
: Task<Stream> OpenRead(string dataBusAttachmentId);
and Task<Dictionary<string, string>> GetMetadata(string dataBusAttachmentId);
and one extra property on IAdvancedApi
: ISyncBus SyncBus { get; }
If you implemented IDataBus
or IAdvancedApi
you most likely did it in order to decorate either service or to function as a test stub. Hopefully it will not be too cumbersome to extend those implementations to support the extra operations.
If you are using the GetCurrentClassLogger()
method of IRebusLoggerFactory
you will have to call GetLogger<YourClass>()
instead β the stack frame walking turned out to be unreliable in some method inlining scenarios.
You will most likely have to update them to a version that is compiled against 3.0.0.