Querybuilder crashes with IConvertible String Types
See original GitHub issueI have a Query which can’t be build with Linq2DB 3.3.0. I can reproduce the error in the Test.Playground.
// this works
string test = "Test";
string test2 = "Test";
var works = table.Any(sampleClass => sampleClass.Value == test
|| sampleClass.Value2.Contains(test2));
// this also works
var works2 = table.Any(sampleClass => sampleClass.Value == "Test"
|| sampleClass.Value2.Contains("Test"));
// But this crashes
string test3 = "Test";
var crashes = table.Any(sampleClass => sampleClass.Value == test3
|| sampleClass.Value2.Contains(test3));
So the Problem seems to be, if i try to reuse a “parameter” here in combination with the Class-Structure. Maybe you can debug the reason, why this query throws an exception or even worse just builds a “where Value = ‘Test’ OR 1=1” The 1=1 part was the worst part 😉.
Exception message:
Syntaxfehler (fehlender Operator) in Abfrageausdruck '()'.
Stack trace:
at System.Data.OleDb.OleDbCommand.ExecuteCommandTextErrorHandling(OleDbHResult hr)
at System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult(tagDBPARAMS dbParams, Object& executeResult)
at System.Data.OleDb.OleDbCommand.ExecuteCommandText(Object& executeResult)
at System.Data.OleDb.OleDbCommand.ExecuteCommand(CommandBehavior behavior, Object& executeResult)
at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.OleDb.OleDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
at LinqToDB.Data.DbCommandProcessor.DbCommandProcessorExtensions.ExecuteReaderExt(IDbCommand cmd, CommandBehavior commandBehavior) in C:\git-ruthardt\linq2db\Source\LinqToDB\Data\DbCommandProcessor\DbCommandProcessorExtensions.cs:line 42
at LinqToDB.Data.DataConnection.ExecuteReader(IDbCommand command, CommandBehavior commandBehavior) in C:\git-ruthardt\linq2db\Source\LinqToDB\Data\DataConnection.cs:line 1401
at LinqToDB.Data.DataConnection.ExecuteReader(CommandBehavior commandBehavior) in C:\git-ruthardt\linq2db\Source\LinqToDB\Data\DataConnection.cs:line 1462
at LinqToDB.Data.DataConnection.ExecuteReader() in C:\git-ruthardt\linq2db\Source\LinqToDB\Data\DataConnection.cs:line 1406
at LinqToDB.Data.DataConnection.QueryRunner.ExecuteReader() in C:\git-ruthardt\linq2db\Source\LinqToDB\Data\DataConnection.QueryRunner.cs:line 495
at LinqToDB.Linq.QueryRunner.ExecuteElement[T](Query query, IDataContext dataContext, Mapper`1 mapper, Expression expression, Object[] ps, Object[] preambles) in C:\git-ruthardt\linq2db\Source\LinqToDB\Linq\QueryRunner.cs:line 729
at LinqToDB.Linq.QueryRunner.<>c__DisplayClass25_0`1.<SetRunQuery>b__0(IDataContext db, Expression expr, Object[] ps, Object[] preambles) in C:\git-ruthardt\linq2db\Source\LinqToDB\Linq\QueryRunner.cs:line 715
at LinqToDB.Linq.ExpressionQuery`1.System.Linq.IQueryProvider.Execute[TResult](Expression expression) in C:\git-ruthardt\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 279
at System.Linq.Queryable.Any[TSource](IQueryable`1 source, Expression`1 predicate)
at Tests.Playground.TestTemplate.SampleSelectTest(String context) in C:\git-ruthardt\linq2db\Tests\Tests.Playground\TestTemplate.cs:line 173
Steps to reproduce
Just copy this code in the class “TestTemplate.cs” in Tests.Playground.
using System;
using System.Linq;
using LinqToDB.Mapping;
using NUnit.Framework;
namespace Tests.Playground
{
using System.Collections.Generic;
using LinqToDB;
public abstract class MySpecialBaseClass : IConvertible, IEquatable<MySpecialBaseClass>
{
[NotNull]
public string Value { get; set; }
protected MySpecialBaseClass(string value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
Value = value;
}
public static bool operator ==(MySpecialBaseClass leftSide, string rightSide)
=> leftSide?.Value == rightSide;
public static bool operator !=(MySpecialBaseClass leftSide, string rightSide)
=> leftSide?.Value != rightSide;
/// <inheritdoc />
public override string ToString() => Value;
/// <inheritdoc />
public override int GetHashCode() => Value.GetHashCode();
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj is string str)
{
return Value.Equals(str);
}
if (obj.GetType() == GetType())
{
return string.Equals(((MySpecialBaseClass)obj).Value, Value);
}
return base.Equals(obj);
}
/// <inheritdoc />
public bool Equals(MySpecialBaseClass other)
{
if (other.GetType() != GetType())
{
// Falls die Auswahllistentypen nicht zusammen passen.
return false;
}
return string.Equals(other.Value, Value);
}
#region IConvertible
public TypeCode GetTypeCode() => TypeCode.String;
public string ToString(IFormatProvider provider) => Value;
/// <summary>
/// if TargetType <see cref="MySpecialBaseClass"/> it returns targettype, else stringAuswahllisten object
/// </summary>
public object ToType(Type conversionType, IFormatProvider provider)
{
if (conversionType.IsSubclassOf(typeof(MySpecialBaseClass))
|| conversionType == typeof(MySpecialBaseClass))
{
return this;
}
return Value;
}
public bool ToBoolean(IFormatProvider provider) { throw new NotImplementedException(); }
public char ToChar(IFormatProvider provider) { throw new NotImplementedException(); }
public sbyte ToSByte(IFormatProvider provider) { throw new NotImplementedException(); }
public byte ToByte(IFormatProvider provider) { throw new NotImplementedException(); }
public short ToInt16(IFormatProvider provider) { throw new NotImplementedException(); }
public ushort ToUInt16(IFormatProvider provider) { throw new NotImplementedException(); }
public int ToInt32(IFormatProvider provider) { throw new NotImplementedException(); }
public uint ToUInt32(IFormatProvider provider) { throw new NotImplementedException(); }
public long ToInt64(IFormatProvider provider) { throw new NotImplementedException(); }
public ulong ToUInt64(IFormatProvider provider) { throw new NotImplementedException(); }
public float ToSingle(IFormatProvider provider) { throw new NotImplementedException(); }
public double ToDouble(IFormatProvider provider) { throw new NotImplementedException(); }
public decimal ToDecimal(IFormatProvider provider) { throw new NotImplementedException(); }
public DateTime ToDateTime(IFormatProvider provider) { throw new NotImplementedException(); }
#endregion
}
public class MyClass : MySpecialBaseClass
{
public const string Example = "Example";
public static ISet<MyClass> AllValues = new HashSet<MyClass>
{
new MyClass(Example)
};
public MyClass(string value)
: base(value)
{
}
public static implicit operator MyClass(string value)
{
if (value == null)
{
return null;
}
return AllValues.FirstOrDefault(a => string.Equals(a.Value, value, StringComparison.OrdinalIgnoreCase)) ?? new MyClass(value);
}
public static implicit operator string(MyClass auswahlliste)
=> auswahlliste?.Value;
}
[TestFixture]
public class TestTemplate : TestBase
{
[Table]
class SampleClass
{
[Column] public int Id { get; set; }
[Column(DataType = DataType.NVarChar, Length = 50)] public MyClass? Value { get; set; }
[Column] public string? Value2 { get; set; }
}
[Test]
public void SampleSelectTest([DataSources] string context)
{
using (var db = GetDataContext(context))
using (var table = db.CreateLocalTable<SampleClass>())
{
// this works
string test = "Test";
string test2 = "Test";
var works = table.Any(sampleClass => sampleClass.Value == test
|| sampleClass.Value2.Contains(test2));
// this also works
var works2 = table.Any(sampleClass => sampleClass.Value == "Test"
|| sampleClass.Value2.Contains("Test"));
// But this crashes
string test3 = "Test";
var crashes = table.Any(sampleClass => sampleClass.Value == test3
|| sampleClass.Value2.Contains(test3));
}
}
}
}
Thanks for the Help!
Environment details
linq2db version: 3.3.0 Database Server: SQL.Server Database Provider: SQL.Server Operating system: Win10 .NET Framework: 4.5.2
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
Extension Methods like In don't use IConvertible #2566
So I made a custom Type which is like an Enum but i can have also a custom String, if it doesn't fit....
Read more >c# - Convert.ChangeType (Error: Object must implement ...
It works just fine when I try to convert an Object (of type List<string> ) back to a List<string> . However, when I...
Read more >ASP.NET Core Report Designer - Casting error when ...
I am using the ASP.NET Core Report Designer 18.2.4 to connect to MySQL 8.0.12 server for Linux (x86_64). The MySQL client is the...
Read more >Toad Data Point Forum - Recent Threads - RSSing.com
Just wondering if anyone seen this crash. While working in QueryBuilder, the GUI just crashed. I added the black squares to hide the...
Read more >IConvertible Interface (System)
Defines methods that convert the value of the implementing reference or value type to a common language runtime type that has an equivalent...
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
First of all I want to note that parameters section printed here only to be used for logging/debug purposes.
You don’t see quotes, because when we render parameter value here, we try to find corresponding SQL literal generator based on parameter type. As you use custom type, there is no such function and we use
ToString
as fallback. You can fix it by adding literal generation method to mapping schema for your type (this will also allow linq2db to generate literals for your type when appropriate instead of parameter):Don’t think we support inheritance here, so probably you cannot use base class here isntead of
MyClass
@MaceWindu thanx the problem is now also fixed in my project 👍 . Just a small remark, in my Output Window, is the generated variable without the ‘’
I write the Traces with: DataConnection.WriteTraceLine = (message, category, _) => Debug.WriteLine(message, category); DataConnection.TurnTraceSwitchOn();
The generated sql looks like this. When used with an IConvertible String.
As you can see, the first Variable @myText is missing ‘’ in the set. Not a big thing. Just a remark.