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.

Querybuilder crashes with IConvertible String Types

See original GitHub issue

I 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:closed
  • Created 2 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
MaceWinducommented, Jun 23, 2021

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):

// check https://github.com/linq2db/linq2db/blob/master/Source/LinqToDB/DataProvider/Access/AccessMappingSchema.cs#L33
SetValueToSqlConverter(typeof(MyClass),   (sb,dt,v) => /*literal build logic here*/);

Don’t think we support inheritance here, so probably you cannot use base class here isntead of MyClass

0reactions
BenKmanncommented, Jun 23, 2021

@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.

DataConnection: BeforeExecute
--  SqlServer.2012
DECLARE @myText NVarChar -- String
SET     @myText = Ben
DECLARE @myText _1 NVarChar(4000) -- String
SET     @myText_1 = N'%Ben%'

As you can see, the first Variable @myText is missing ‘’ in the set. Not a big thing. Just a remark.

Read more comments on GitHub >

github_iconTop 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 >

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