Entity Framework Core 6 - trim all returned strings by command interception - string

When I was working with EF (System.Data.Entity) I successfully used an interceptor to automatically trim all existing strings in the database.
The IDbCommandTreeInterceptor is described in this post: EF6.1–Workaround Trailing Blanks Issue in String Joins.
public class StringTrimmerInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
{
var queryCommand = interceptionContext.Result as DbQueryCommandTree;
if (queryCommand != null)
{
var newQuery = queryCommand.Query.Accept(new StringTrimmerQueryVisitor());
interceptionContext.Result = new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
newQuery);
}
}
}
private class StringTrimmerQueryVisitor : DefaultExpressionVisitor
{
private static readonly string[] _typesToTrim = { "nvarchar", "varchar", "char", "nchar" };
public override DbExpression Visit(DbNewInstanceExpression expression)
{
var arguments = expression.Arguments.Select(a =>
{
var propertyArg = a as DbPropertyExpression;
if (propertyArg != null && _typesToTrim.Contains(propertyArg.Property.TypeUsage.EdmType.Name))
return EdmFunctions.Trim(a);
return a;
});
return DbExpressionBuilder.New(expression.ResultType, arguments);
}
}
}
I need some help to implement the same functionality by EntityFrameworkCore DbCommandInterceptor.

Related

How to use a function put in using a constructor

So I have this class:
class Sigil {
constructor(name = "", type = "", func = (oppositeCard, oppositeCardLane) => { }) {
this.name = name;
this.type = type;
this.function = func
}
Activate(oppositeCard, oppositeCardLane) {
};
}
var fly = new Sigil("Fly", "OnAttack", (oppositeCard, oppositeCardLane) => {
oppositeCard = cardLib.blank;
return oppositeCard;
})
What I wan to do is use that function that I put in using the constructor. So like i want to call the "func" function using the Activate method
All you do is call this.function.
class Sigil {
...
Activate(){
this.function();
}
...
}

Could haxe macro be used to detect when object is dirty (any property has been changed)

Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};

In YamlDotNet: Is there a way to output a null value as an empty string in a sequence?

When writing a sequence in an IYamlTypeConverter you might use some code like this:
public class MyObjectConverter : IYamlTypeConverter {
public MyObjectConverter() {}
public bool Accepts(Type type) { return typeof(IMyObject) == type || typeof(IMyObject[]) == type; }
public object ReadYaml(IParser parser, Type type) { return null; }
public void WriteYaml(IEmitter emitter, object value, Type type) {
var itemVal = value as IMyObject;
if (itemVal != null)
emitter.Emit(new Scalar(itemVal.GetID()));
else {
var arrayVal = value as IMyObject[];
emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Block));
if (arrayVal != null) {
foreach (var item in arrayVal)
if (item != null) emitter.Emit(new Scalar(item.GetID()));
else emitter.Emit(new Scalar("null"));
}
emitter.Emit(new SequenceEnd());
}
}
}
By calling emitter.Emit(new Scalar("null")) you would get a 'null' entry in the sequence, but if you leave the serialization up to YamlDotNet, it would be serialized as '' (empty string).
How do you output a null value in a sequence as an empty string when writing a custom IYamlTypeConverter?
One way to achieve this is to create a custom IEventEmitter that will add this logic:
public class NullStringsAsEmptyEventEmitter : ChainedEventEmitter
{
public NullStringsAsEmptyEventEmitter(IEventEmitter nextEmitter)
: base(nextEmitter)
{
}
public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
{
if (eventInfo.Source.Type == typeof(string) && eventInfo.Source.Value == null)
{
emitter.Emit(new Scalar(string.Empty));
}
else
{
base.Emit(eventInfo, emitter);
}
}
}
You then register it like this:
var serializer = new SerializerBuilder()
.WithEventEmitter(nextEmitter => new NullStringsAsEmptyEventEmitter(nextEmitter))
.Build();
Here's a fiddle with this code
It seems you can represent a null value simply with '~', according to http://www.yaml.org/refcard.html

Haxe – Proper way to implement Map with Int64 keys that can be serialized (native target)

I need to know, what would be proper way to implement Maps with 64 bit keys. There will not be so many items in them, I just need to use various bits of the key for various things with large enough address space and I need it to be very fast, so String keys would probably be too slow. So far I tried:
import haxe.Int64;
import haxe.Unserializer;
import haxe.Serializer;
class Test {
static function main () {
var key:Int64 = 1 << 63 | 0x00000001;
var omap:Map<Int64, String> = new Map<Int64, String>();
omap.set(key, "test");
var smap:Map<Int64, String> = Unserializer.run(Serializer.run(omap));
var key2:Int64 = 1 << 63 | 0x00000001;
trace(key+" "+smap.get(key2));
}
}
http://try.haxe.org/#7CDb2
which obviously doesn't work, because haxe.Int64 creates an object instance. Using cpp.Int64 works, because it for some reason falls back to 32 bit integer in my cpp code and I don't know what am I doing wrong. How can I force it to "stay" 64 bit, or should I do it some other way?
EDIT: This is currently not working on native targets due to bug / current implementation in hxcpp: https://github.com/HaxeFoundation/hxcpp/issues/523
I figured out this workaround / wrapper, which may not be the most efficient solution possible, but it seems to work.
import haxe.Int64;
import haxe.Unserializer;
import haxe.Serializer;
class Test {
static function main () {
var key:Int64 = Int64.make(1000,1);
var omap:Int64Map<String> = new Int64Map();
omap.set(key, "test");
var smap:Int64Map<String> = Unserializer.run(Serializer.run(omap));
var key2:Int64 = Int64.make(1000,1);
trace(key+" "+smap.get(key2));
}
}
class Int64Map<V> {
private var map:Map<Int64,V>;
public function new() : Void {
this.map = new Map<Int64,V>();
}
public function set(key:Int64, value:V):Void {
this.map.set(key, value);
}
public inline function get(key:Int64):Null<V> {
var skey:Null<Int64> = getMapKey(key);
if (skey != null) return this.map.get(skey);
return null;
}
public inline function exists(key:Int64):Bool {
return (getMapKey(key) != null);
}
public function remove( key : Int64 ) : Bool {
var skey:Null<Int64> = getMapKey(key);
if (skey != null) return this.map.remove(skey);
return false;
}
public function keys() : Iterator<Int64> {
return this.map.keys();
}
public function toString() : String {
return this.map.toString();
}
public function iterator() : Iterator<V> {
return this.map.iterator();
}
private function getMapKey(key:Int64):Null<Int64> {
for (ikey in this.map.keys()){
if (Int64.eq(key, ikey)){
return ikey;
}
}
return null;
}
}
http://try.haxe.org/#57686

DNX (rc1-final): IHttpConnectionFeature not found

Using the latest rc1-final version of ASP.NET 5, I'm attempting to find the remote IP address inside an Azure API App controller method.
When running the code, 'context' is this.HttpContext, inside the controller method.
But feature is coming back null, since the feature doesn't exist.
IHttpConnectionFeature feature = context.Features.Get<IHttpConnectionFeature>();
Does anything have to be enabled in the configuration to have this feature be available?
Thanks,
Kirk
I had the same problem.
The following code works for me:
public async Task<IActionResult> Index()
{
if (!UserID.HasValue)
{
UpdateRemoteIp(HttpContext);
var remoteIpAddress = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
if (remoteIpAddress == null)
{
throw new Exception("Cannot determine client IP");
}
await _userService.LoginAnonymous(remoteIpAddress);
string url = UriHelper.GetDisplayUrl(Request);
return Redirect(url);
}
PrepareViewModel();
return View("Index", ViewModel);
}
private static void UpdateRemoteIp(HttpContext httpContext)
{
var xForwardedForHeaderValue = httpContext.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName);
if (xForwardedForHeaderValue != null && xForwardedForHeaderValue.Length > 0)
{
IPAddress ipFromHeader;
int? port;
if (IPAddressWithPortParser.TryParse(xForwardedForHeaderValue[0], out ipFromHeader, out port))
{
var connection = httpContext.Connection;
var remoteIPString = connection.RemoteIpAddress?.ToString();
if (!string.IsNullOrEmpty(remoteIPString))
{
httpContext.Request.Headers[XOriginalIPName] = remoteIPString;
}
if (port.HasValue)
{
if (connection.RemotePort != 0)
{
httpContext.Request.Headers[XOriginalPortName] = connection.RemotePort.ToString(CultureInfo.InvariantCulture);
}
connection.RemotePort = port.Value;
}
connection.RemoteIpAddress = ipFromHeader;
}
}
}
Hope it helps you

Resources