Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query :: optional navigations null-ref protection logic doesn't work for some cases involving multiple optional navs and method calls #5613

Closed
maumar opened this issue Jun 1, 2016 · 3 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@maumar
Copy link
Contributor

maumar commented Jun 1, 2016

Found during investigation of #5481

model:

    public class Shipment
    {
        public int Id { get; set; }
        public string CarrierName { get; set; }
        public int? CargoReportId { get; set; }
        public Report CargoReport { get; set; }
        public int? AltCargoReportId { get; set; }
        public Report AltCargoReport { get; set; }
    }

    public class Report
    {
        public int Id { get; set; }
        public string Reference { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<Shipment> Shipments { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=.;Database=Repro5613;Trusted_Connection=True;MultipleActiveResultSets=true;");
        }
    }

query:

                var query = ctx.Shipments
                     .Where(s => s.CargoReport.Reference.Contains("whatever")
                             || s.AltCargoReport.Reference.Contains("whatever"));

relevant query plan fragment:

(t3.Outer.Outer.Inner != null ? t3.Outer.Outer.Inner.Reference : null).Contains(
            value: whatever
        )

this will null ref if Outer.Outer.Inner is null

@maumar
Copy link
Contributor Author

maumar commented Aug 2, 2016

moving to 1.0.1 per triage comment in #6177

@divega
Copy link
Contributor

divega commented Aug 12, 2016

Pulling from 1.0.1 into 1.1.0 because the fix has grown complex enough that we are not longer confident we should include it in a patch release.

cc @maumar @Eilon

maumar added a commit that referenced this issue Aug 12, 2016
…c doesn't work for some cases involving multiple optional navs and method calls
maumar added a commit that referenced this issue Aug 15, 2016
…me cases where non-nullable type is expected

Problem was that we were not compensating for nullability change properly for some cases, leading to compilation errors is some cases and runtime errors in others.

e.g.
context.Tags.Where(t => t.Gear.HasSoulPatch)

would get translated to:
context.Tags.Where(t => (bool)(t.Gear != null ? t.Gear.HasSoulPatch : null))

but now we will translate it to:
context.Tags.Where(t => (t.Gear != null ? t.Gear.HasSoulPatch : null) == true)

This ensures type consistency as well as prevents exception being thrown at runtime, when we would sometimes try to cast null value to bool.
We do similar rewrite for other "search conditions"

Also modified one of the test models and added tests for #5613, and fixed a few minor bugs.
maumar added a commit that referenced this issue Aug 15, 2016
…me cases where non-nullable type is expected

Problem was that we were not compensating for nullability change properly for some cases, leading to compilation errors is some cases and runtime errors in others.

e.g.
context.Tags.Where(t => t.Gear.HasSoulPatch)

would get translated to:
context.Tags.Where(t => (bool)(t.Gear != null ? t.Gear.HasSoulPatch : null))

but now we will translate it to:
context.Tags.Where(t => (t.Gear != null ? t.Gear.HasSoulPatch : null) == true)

This ensures type consistency as well as prevents exception being thrown at runtime, when we would sometimes try to cast null value to bool.
We do similar rewrite for other "search conditions"

Also modified one of the test models and added tests for #5613, and fixed a few minor bugs.

CR: Smit
maumar added a commit that referenced this issue Aug 24, 2016
…c doesn't work for some cases involving multiple optional navs and method calls

Problem was that we were providing null protection in case of optional navigation access, but that did not include further calling methods on top of them.
If the navigation was null, the member access would return null and we would try to call a method on it, which results in NRE.

Fix is to introduce a new reducible expression that represents conditional access to a method or a member. In memory this gets rewritten to a Block expression that recursively evaluates it's caller, assigns it to a variable and depending on the value, either returns null or performs the required access operation. This is superior to using Conditional expression that we did before, because the caller only gets evaluated once, rather than N times.

Also fixes related issue #6261 - DateTime converted to Nullable<DateTime> inside optional navigation property, throws exception on AddDays.
maumar added a commit that referenced this issue Aug 24, 2016
…c doesn't work for some cases involving multiple optional navs and method calls

Problem was that we were providing null protection in case of optional navigation access, but that did not include further calling methods on top of them.
If the navigation was null, the member access would return null and we would try to call a method on it, which results in NRE.

Fix is to introduce a new reducible expression that represents conditional access to a method or a member. In memory this gets rewritten to a Block expression that recursively evaluates it's caller, assigns it to a variable and depending on the value, either returns null or performs the required access operation. This is superior to using Conditional expression that we did before, because the caller only gets evaluated once, rather than N times.

Also fixes related issue #6261 - DateTime converted to Nullable<DateTime> inside optional navigation property, throws exception on AddDays.
maumar added a commit that referenced this issue Aug 26, 2016
…c doesn't work for some cases involving multiple optional navs and method calls

Problem was that we were providing null protection in case of optional navigation access, but that did not include further calling methods on top of them.
If the navigation was null, the member access would return null and we would try to call a method on it, which results in NRE.

Fix is to introduce a new reducible expression that represents conditional access to a method or a member. In memory this gets rewritten to a Block expression that recursively evaluates it's caller, assigns it to a variable and depending on the value, either returns null or performs the required access operation. This is superior to using Conditional expression that we did before, because the caller only gets evaluated once, rather than N times.

Also fixes related issue #6261 - DateTime converted to Nullable<DateTime> inside optional navigation property, throws exception on AddDays.

CR: Andrew
maumar added a commit that referenced this issue Aug 26, 2016
…c doesn't work for some cases involving multiple optional navs and method calls

Problem was that we were providing null protection in case of optional navigation access, but that did not include further calling methods on top of them.
If the navigation was null, the member access would return null and we would try to call a method on it, which results in NRE.

Fix is to introduce a new reducible expression that represents conditional access to a method or a member. In memory this gets rewritten to a Block expression that recursively evaluates it's caller, assigns it to a variable and depending on the value, either returns null or performs the required access operation. This is superior to using Conditional expression that we did before, because the caller only gets evaluated once, rather than N times.

Also fixes related issue #6261 - DateTime converted to Nullable<DateTime> inside optional navigation property, throws exception on AddDays.

CR: Andrew
maumar added a commit that referenced this issue Aug 26, 2016
…c doesn't work for some cases involving multiple optional navs and method calls

Problem was that we were providing null protection in case of optional navigation access, but that did not include further calling methods on top of them.
If the navigation was null, the member access would return null and we would try to call a method on it, which results in NRE.

Fix is to introduce a new reducible expression that represents conditional access to a method or a member. In memory this gets rewritten to a Block expression that recursively evaluates it's caller, assigns it to a variable and depending on the value, either returns null or performs the required access operation. This is superior to using Conditional expression that we did before, because the caller only gets evaluated once, rather than N times.

Also fixes related issue #6261 - DateTime converted to Nullable<DateTime> inside optional navigation property, throws exception on AddDays.

CR: Andrew
@maumar
Copy link
Contributor Author

maumar commented Aug 26, 2016

Fixed in 7472a67

@maumar maumar closed this as completed Aug 26, 2016
@maumar maumar added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Aug 26, 2016
@ajcvickers ajcvickers modified the milestones: 1.1.0-preview1, 1.1.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

5 participants