Question

The database I'm working with stores a pair of double values in two integer columns.

IOW, Department is a double with values such as 42.12, but is stored in a Dept column (which holds 42 in this case) and a Subdept column (which holds 12 in this case). Don't ask me why (because you'd be disappointed; I can't tell you why, because I don't know).

I need to get a subset of data such as "all the department records between 8.79 and 98.87"

I have this code:

public IEnumerable<InventoryItem> GetDepartmentRange(double deptBegin, double deptEnd, string dbContext)
{
    LoadInventoryItems(dbContext);
    // Break the doubles into their component parts:
    var deptStartWhole = (int)Math.Truncate(deptBegin);
    var startFraction = (int)((deptBegin - deptStartWhole) * 100);
    var deptEndWhole = (int)Math.Truncate(deptEnd);
    var endFraction = (int)((deptBegin - deptEndWhole) * 100);

    return inventoryItems
        .Where(d => d.dept >= deptStartWhole)
        .Where(e => e.subdept >= startFraction)
        .Where(f => f.dept <= deptEndWhole)
        .Where(g => g.subdept >= endFraction)
        //.Where(g => g.subdept <= endFraction)
        .OrderBy(o => o.dept)
        .ThenBy(s => s.subdept);
}

...but it doesn't quite work - with the above query (Depts between 8.79 and 98.87) it shows depts that are 98.88, which is one beyond what I want.

I tried the commented-out line, but that made it even worse (nothing returned at all).

My intuition tells me I may need a "let" here, but don't know just how to go about it.

UPDATE

enter image description here

Was it helpful?

Solution

Since in you're example you're multiplying the fraction by 100, i'm assuming the subdept value would only have two digits. If it's the case, perhaps you could try the following code:

public IEnumerable<InventoryItem> GetDepartmentRange(double deptBegin, double deptEnd, string dbContext)
{           
  LoadInventoryItems(dbContext);

  return inventoryItems
    .Where(d => ((d.dept * 100 + d.subdept) >= deptBegin * 100) &&       
                ((d.dept * 100 + d.subdept) <= deptEnd * 100))
    .OrderBy(o => o.dept)
    .ThenBy(s => s.subdept);
}

OTHER TIPS

Your endFraction calculation is wrong:

public IEnumerable<InventoryItem> GetDepartmentRange(double deptBegin, double deptEnd, string dbContext)
{
    LoadInventoryItems(dbContext);
    // Break the doubles into their component parts:
    int deptStartWhole = (int)Math.Truncate(deptBegin);
    int startFraction = (int)((deptBegin - deptStartWhole) * 100);
    int deptEndWhole = (int)Math.Truncate(deptEnd);
    int endFraction = (int)((deptEnd - deptEndWhole) * 100);

    return inventoryItems
        .Where(d => d.dept >= deptStartWhole)
        .Where(e => e.subdept >= startFraction)
        .Where(f => f.dept <= deptEndWhole)
        .Where(g => g.subdept >= endFraction)
        .OrderBy(o => o.dept)
        .ThenBy(s => s.subdept);
}

Your condition is not correct. Consider following:

int deptStartWhole = 8;
int startFraction = 79;
int deptEndWhole = 98;
int endFraction = 87;

and your condition is:

d.dept >= deptStartWhole && d.subdept >= startFraction
&& d.dept <= deptEndWhole && d.subdept <= endFraction

it will not return row with dept = 12 and subdept = 32, because 32 >= 79 (d.subdept >= startFraction check) is not true.

I think your condition should be

((d.dept == deptStartWhole && d.subdept >= startFraction) || d.dept > deptStartWhole)
&& ((d.dept == deptEndWhole && d.subdept <= endFraction) || d.subdept < deptEndWhole)

It checked subdept only when dept is exactly the same, and otherwise just check dept part, because that's the important one.

return inventoryItems
    .Where(d => ((d.dept == deptStartWhole && d.subdept >= startFraction) || d.dept > deptStartWhole)
                && ((d.dept == deptEndWhole && d.subdept <= endFraction) || d.subdept < deptEndWhole))
    .OrderBy(o => o.dept)
    .ThenBy(s => s.subdept);

You are using a wrong variable in your calculation here:

var endFraction = (int)((deptBegin - deptEndWhole) * 100);

Replace deptBegin with deptEnd to fix this.

Making this change appears to produce the desired values when tested with the following code:

public void ShowDeptRange(double deptBegin, double deptEnd)
{
    // Break the doubles into their component parts:
    var deptStartW = (int)Math.Truncate(deptBegin);
    var deptStartF = (int)((deptBegin - deptStartW) * 100);
    var deptEndW = (int)Math.Truncate(deptEnd);
    var deptEndF = (int)((deptEnd - deptEndW) * 100);

    Console.WriteLine("{0}.{1}, {2}.{3}",
        deptStartW, deptStartF, deptEndW, deptEndF);
}

void Main()
{
    ShowDeptRange(8.79, 98.87);
}

Also see this answer, which addresses problems with your query's logic.

A suggestion: create a function that takes in the deptNumber and deptSubNumber, and returns a decimal. Then, use that function in-line in the .Where() statement to process the numbers as a single number, rather than using separate logic (treating dept and sub-dept separately) .

An alternative suggestion: is it possible to create a calculated column on the database that simply combines the two fields together in the database, and returns it as a decimal?

Then, use that function in-line in the .Where() statement to process the numbers as a single number, rather than using separate logic (treating dept and sub-dept separately).

Following this, all of the department/sub-department logic in the C# code would be moot.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top