linq2db: MySQL: Data is Null. This method or property cannot be called on Null values.

This may not be caused by LINQ2DB, but hopefully someone already came across this issue. I’m using LINQ2DB to access a MySQL instance (5.6.35 / Percona 80).

There’s one particular query that accesses a view from one db that does a cross-db select (may not be relevant), something like:

SELECT id, name FROM other_database.some_table st WHERE st.id = 1234;

On the LINQ2DB site the query is super simple as well:

var record = (from sv in db.SomeView where sv.Id == 1234 select sv).FirstOrDefault();

99% of the time, this query works without issues. Sometimes though, I’m getting:

Exception message: Data is Null. This method or property cannot be called on Null values. Stack trace:

at MySql.Data.MySqlClient.MySqlDataReader.GetFieldValue(Int32 index, Boolean checkNull)\r\n   at MySql.Data.MySqlClient.MySqlDataReader.GetString(Int32 i
at lambda_method(Closure , QueryContext , IDataContext , IDataReader , Expression , Object[] )\r\n   at LinqToDB.Linq.Query`1.<Map>d__69.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at LinqToDB.Linq.Builder.FirstSingleBuilder.FirstSingleContext.<>c__DisplayClass12`1.<BuildQuery>b__b(QueryContext ctx, IDataContext db, Expression expr, Object[] ps)
at LinqToDB.Linq.ExpressionQuery`1.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
at MyNamespace.MyFunction(Int32 campaignId, Int32 dealerId) in [my source code]

Once I get this error, subsequent requests fail with the same message (and always the same spot). Most of the time, restarting the application pool fixes the problem, but I’ve seen it where it wasn’t fixing it.

If I put a breakpoint right before the error and extract the SQL query and then run that query in MySQL Workbench the query runs fine and none of the returned rows are null. However, LINQ2DB complains that the results set came back with nulls for ints. It’s almost as if MySQL returns a blank row to my app, but a proper result set for MySQL Workbench (same exact query). Is there a way I could catch the raw data coming back from MySQL before LINQ2DB tries to deserialize?

It’s very strange and very hard to reproduce… I was not able to find a pattern (yet).

Any ideas? Thanks.

Steps to reproduce

None, unfortunately…

Environment details

linq2db version: 1.8.3
Database Server: MySQL 5.6
Database Provider: MySqlDataProvider
Operating system: Windows Server 2012 R2
Framework version: .NET Framework 4.6.1

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 1
  • Comments: 41 (38 by maintainers)

Most upvoted comments

Originally, I was seeing these issues in one spot that was using a database view. It was happening somewhat randomly (once or twice a day). I was not able to reproduce that issue and it was not happening when running the test suite, only in production.

Since I thought the issue was with the MySQL view I went ahead and got rid of the view. It’s now running against tables; doesn’t use views anymore. After I removed the views I was able to trigger the issue within the test suite.

The create statement for the emails table is:

CREATE TABLE `email_addresses` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(128) NOT NULL,
  `unsubscribed` tinyint(1) NOT NULL DEFAULT '0',
  `is_valid_for_analysis` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`) USING BTREE,
  UNIQUE KEY `id` (`id`,`unsubscribed`) USING BTREE,
  KEY `idx_analysis` (`id`,`is_valid_for_analysis`)
) ENGINE=InnoDB AUTO_INCREMENT=5230558 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;

and the one for the vehicles table (the one that works even though it’s very similar to the emails table)

CREATE TABLE `vehicles` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `vin` varchar(17) NOT NULL,
  `year` int(4) NOT NULL,
  `make` varchar(50) NOT NULL,
  `model` varchar(50) NOT NULL DEFAULT '',
  `is_cleaned` tinyint(1) DEFAULT '0',
  `blackbook_value` decimal(10,4) DEFAULT NULL,
  `blackbook_last_updated` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `year` (`year`) USING BTREE,
  KEY `vehicle` (`vin`,`year`,`make`,`model`)
) ENGINE=InnoDB AUTO_INCREMENT=24913935 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC;

@ili yes, I did migrate to VS2017

@MaceWindu I’ve hit that exact same issue (double dots “…”) with master… after rolling back to 1.8.3 this issue goes away

“there is no null values in any column of dr” – the email column is null, but it’s a string, so it shouldn’t be an issue. Here’s what “dr” looks like:

image

“mapping expression doesn’t try to access column with out-of-range index” – how do I check for this?

“mapping expression does what it needs for current query” – well… here’s what I was able to fish out from the debug view:

.Lambda #Lambda1<System.Func`6[LinqToDB.Linq.QueryContext,LinqToDB.IDataContext,System.Data.IDataReader,System.Linq.Expressions.Expression,System.Object[],Denali.Core.Entities.Organization.Dto.ProspectDetail]>(
    LinqToDB.Linq.QueryContext $context,
    LinqToDB.IDataContext $dctx,
    System.Data.IDataReader $rd,
    System.Linq.Expressions.Expression $expr,
    System.Object[] $ps) {
    .Block(
        MySql.Data.MySqlClient.MySqlDataReader $ldr,
        Denali.Core.Entities.Organization.Dto.ProspectDetail $ProspectDetail1) {
        $ldr = (MySql.Data.MySqlClient.MySqlDataReader)$rd;
        $ProspectDetail1 = .New Denali.Core.Entities.Organization.Dto.ProspectDetail(){
            ProspectDetailId = #(System.Int32)((System.UInt32).Call $ldr.GetValue(0)),
            ProspectId = #(System.Int32)((System.UInt32).Call $ldr.GetValue(1)),
            CustomerId = #(System.Int32)((System.UInt32).Call $ldr.GetValue(2)),
            CustomerKey = .If (
                .Call $ldr.IsDBNull(3)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(3)
            },
            Proof = .If (
                .Call $ldr.IsDBNull(4)
            ) {
                null
            } .Else {
                .New System.Nullable`1[System.Int32](.Call $ldr.GetInt32(4))
            },
            FirstName = .Call $ldr.GetString(5),
            LastName = .Call $ldr.GetString(6),
            Street1 = .If (
                .Call $ldr.IsDBNull(7)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(7)
            },
            Street2 = .If (
                .Call $ldr.IsDBNull(8)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(8)
            },
            City = .If (
                .Call $ldr.IsDBNull(9)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(9)
            },
            State = .If (
                .Call $ldr.IsDBNull(10)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(10)
            },
            Zip = .If (
                .Call $ldr.IsDBNull(11)
            ) {
                null
            } .Else {
                .Call ((System.UInt32).Call $ldr.GetValue(11)).ToString()
            },
            Phone = .If (
                .Call $ldr.IsDBNull(12)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(12)
            },
            Email = .Call $ldr.GetString(13),
            VIN = .If (
                .Call $ldr.IsDBNull(14)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(14)
            },
            Year = .Call (.If (
                .Call $ldr.IsDBNull(15)
            ) {
                0
            } .Else {
                .Call $ldr.GetInt32(15)
            }).ToString(),
            Make = .If (
                .Call $ldr.IsDBNull(16)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(16)
            },
            Model = .If (
                .Call $ldr.IsDBNull(17)
            ) {
                null
            } .Else {
                .Call $ldr.GetString(17)
            }
        };
        $ProspectDetail1
    }
}

Here’s what my query looks like:

image

What I find interesting is that both Phone and VIN are strings, just like Email, but those two are wrapped with a IsDBNull check while Email is not…

Also, what’s interesting is that if I force the null check by doing Email = ea.Email == null ? null : ea.Email instead of just Email = ea.Email then it works…

Thoughts?