Using: MVC 5, C#, VS 2013, EF6 with CodeFirst, SQL Server 2012
I have tried the four different ways to get the data without any issues.
IQueryable<vw_Results> qryResults = _db.vw_Results;
The problem I am encountering is that I have 13 filter options and the code for all 13 follow the same logic:
string fmVal = string.Empty;
if (!string.IsNullOrEmpty(form["Locations"]))
{
fmVal = form["Locations"].ToString();
qryResults = qryResults.Where(w => w.LOCATION.CompareTo(fmVal) == 0);
}
if (!string.IsNullOrEmpty(form["ddActionLevels"]))
{
//qryResults = qryResults.Where(w => w.PAL_ID==form["ddActionLevels"].ToString());
vbVal = form["ddActionLevels"].ToString(); ;
//qryResults = qryResults.Where(w => w.AL == vbVal);
qryResults.Where(w => w.AL.CompareTo(vbVal) >= 0);
}
if (!string.IsNullOrEmpty(form["btnGenericRpt"]))
{
qryResults.Where(w => w.LOCATION != "BB1");
}
if (!string.IsNullOrEmpty(form["ddProjects"]))
{
vbVal = form["ddProjects"].ToString();
qryResults.Where(w => w.PROJECT == vbVal);
}
//...
myModel.Results = qryResults.ToList();
return View(myModel);
If I only provide 1 filter, I get the data that I want. As soon as I provide more than 1 filter, I get the "Enumeration yielded no results" yet the data-set from the first filter does contain the data I am filtering on.
The main problem I see with your code is the lines like this:
qryResults.Where(w => w.AL.CompareTo(vbVal) >= 0);
You start with qryResults, compute a .Where(...) but you don't re-assign the query back to qryResults.
Try this:
qryResults = qryResults.Where(w => w.AL.CompareTo(vbVal) >= 0);
Although this doesn't explain why you're getting no results back. That'll be a question you should tackle when you get the code right.
To get filtered data and work from there I needed to add .ToList(), after Where and assign filtered results further:
class Program
{
static void Main(string[] args)
{
var testList = new List<Test>()
{
new Test() { Field4 = false, Field1 = 19845623, Field3 = 1658006 },
new Test() { Field4 = false, Field1 = 19845645, Field3 = 1658056 },
new Test() { Field4 = false, Field1 = 19845665, Field3 = 1658045 },
new Test() { Field4 = false, Field1 = 19845678, Field3 = 1658078 },
new Test() { Field4 = false, Field1 = 19845698, Field3 = 1658098 },
};
var test = testList.Where(x => x.Field4 == false).ToList();
Console.WriteLine();
}
}
internal class Test
{
public int Field1 { get; set; }
public long Field3 { get; set; }
public bool Field4 { get; set; }
}
Hope this is helpful!
Instead of doing multiple where clauses like you code exhibits, you could try using a predicatebuilder ( ref http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx) to build the expression for your where clause based on different if statements and then use it on qryResults at the end.
Here is an example of how you can use predicateBuilder
void Main()
{
var myQuery = new List<Car> {
new Car {IsRed = true, IsConvertible = true },
new Car {IsRed = true, IsConvertible = false },
new Car {IsRed = false, IsConvertible = true },
new Car {IsRed = false, IsConvertible = false }
}.AsQueryable();
Expression<Func<Car, bool>> isRed = c => c.IsRed;
Expression<Func<Car, bool>> isConvertible = c => c.IsConvertible;
var isRedConvertible = isRed.And(isConvertible);
var redConvertible = myQuery.Where(isRedConvertible);
}
public class Car
{
public bool IsRed {get;set;}
public bool IsConvertible {get;set;}
}
Wow, I can't believe what the problem/solution was to my issue. Because I was using the same variable (vbVal) in the .WHERE clause, when it was time to get the data, the query was using the last value of vbVal and thus not returning any data back. I'm guessing that LINQ uses ByRef for variables so my query would end up as:
vbVal = form["filter1"]; {"North America"}
qryResults = qryResults.Where (w=>w.col1 == vbVal);
vbVal = form["filter2"]; {"USA"}
qryResults = qryResults.Where (w=>w.col2 == vbVal);
vbVal = form["filter3"]; {"New York"}
qryResults = qryResults.Where (w=>w.col2 == vbVal);
The query back to SQL would be:
Select col1, col2, col3 From dbTable
Where col1 = "New York" and col2 = "New York" and col3 = "New York"
Assigning each filter option to a unique variable solved my problem.
Thank you all for providing solutions.
Related
I blocked in below step
var ids = _repository.GetIQueryable<Customers>().Where(lrt => lrt.IsActive == true &&
lrt.NextRoleId == defaultRoleSetting.RoleId &&
lrt.NextUserId == null).Select(x => x.MasterId).Distinct().Take(100).ToHashSet();
I tried this but I don't find the right Returns syntax
_mockRepository.Setup(s => s.GetIQueryable<Customers>()).Returns<List<int>>(ids =>
{
return ????;
});
As you are creating a setup for GetIQueryable<Customers> you'd not return a list of integers, but instead an IQueryable of Customers objects that are filtered afterwards:
IQueryable<Customers> models = new Customers[] {
new Customers() { MasterId = 1, IsActive = true, NextRoleId = nextRoleId, ... },
new Customers() { MasterId = 2, IsActive = false, NextRoleId = nextRoleId, ... },
new Customers() { MasterId = 3, IsActive = true, NextRoleId = nextRoleId, ... },
}).AsQueryable();
_mockRepository
.Setup(s => s.GetIQueryable<Customers>())
.Returns(models);
In this sample, you create an array of Customers objects and set the properties of the customers so that the filter afterwards works on the IQueryable. Which properties to set on the Customers objects depends on the classes and your test case.
by below code my issue solved thanks every one.
var fakeCustomers = FakeCustomers();
_repository.Setup(s => s.GetIQueryable<Customers()).Returns(fakeCustomers.AsQueryable());
private List<Customers> FakeCustomers()
{
string fakeData = #"[{
'Id': '118',
'CreatedBy':'00000000-0000-0000-0000-000000000000',
'SId':'4',
'UserId':'00000000-0000-0000-0000-000000000000',
'NId':'7'
}]";
return JsonConvert.DeserializeObject<List<Customers>>(fakeData);
}
If I have the following LINQ query:
var outstandingDataTotalData = from t1 in dtTotal.AsEnumerable()
join t2 in dtOutstandingData.AsEnumerable() on
new
{
priv_code = t1["priv_code"],
pri_ded = t1["pri_ded"].ToString().Trim()
} equals
new
{
priv_code = t2["priv_code"],
pri_ded = t2["pri_ded"].ToString().Trim()
}
into ps
from t2 in ps.DefaultIfEmpty()
select new
{
adjustment_value = t2 == null ? string.Empty : t2["adjustment_value"].ToString(),
amount_outstanding = t2 == null ? string.Empty : t2["amount_outstanding"].ToString(),
amount_outstanding_priv = t2 == null ? string.Empty : t2["amount_outstanding_priv"].ToString(),
amount_outstanding_ded = t2 == null ? string.Empty : t2["amount_outstanding_ded"].ToString(),
diff_outstanding = t2 == null ? string.Empty : t2["diff_outstanding"].ToString(),
exchange_rate = t2 == null ? string.Empty : t2["exchange_rate"].ToString(),
SalYear = t2 == null ? string.Empty : t2["sal_year"].ToString(),
SalMonth = t2 == null ? string.Empty : t2["sal_mon"].ToString()
};
Now outstandingDataTotalData is a list of anonymous type. And I have the following class:
public class AdjustmentTotal
{
public string SalYear { get; set; }
public string SalMonth { get; set; }
public string Value { get; set; }
}
How to loop through outstandingDataTotalData properties to fill List<AdjustmentTotal> as the following example:
If the result set of outstandingDataTotalData =
[0]{ adjustment_value = "100.00", amount_outstanding = "80.00", amount_outstanding_priv = "60.00", amount_outstanding_ded = "30.52", diff_outstanding = "0.36", exchange_rate = "", SalYear = "2018", SalMonth = "1" }
[1]{ adjustment_value = "1500.00", amount_outstanding = "5040.00", amount_outstanding_priv = "", amount_outstanding_ded = "", diff_outstanding = "0.36", exchange_rate = "", SalYear = "2018", SalMonth = "1" }
I want the result set of List<AdjustmentTotal> as:
2018 1 100.00
2018 1 1500.00
2018 1 80.00
2018 1 5040.00
2018 1 60.00
2018 1
2018 1 30.52
2018 1
2018 1 0.36
2018 1 0.36
2018 1
2018 1
Make your life easy, don't extract to separate properties. Make the extract as an array:
select new {
someArray = new[]{
t2["adjustment_value"].ToString(),
t2["amount_outstanding"].ToString(),
t2["amount_outstanding_priv"].ToString(),
t2["amount_outstanding_ded"].ToString(),
...
},
SalYear = ...,
}
So you end up with an object with 3 properties, two strings SalXxx and an array of strings (the other values). The array of strings means you can use the LINQ SelectMany it to flatten it. You'll see in the msdn example they have owners with lists of pets (variable number of pets but your values are fixed number) and after selectmany it's flattened to a list where the owner repeats and there is one pet. Your lowercases values are the pets, the SalXxx values are the owners
Once you get a working query you can actually integrate it into the first query ..
Sorry for not posting a full example (and I skipped the null checks for clarity) - the code is very hard to work with on a cellphone
Edit:
So, you say you want the results in a particular order. Both Select and SelectMany have a version where they will give the index of the item, and we can use that.. because you basically want to have these objects:
var obj = new [] {
new { SalYear = 2018, SalMonth = 1, C = new[] { "av1", "ao1", "aop1", "aod1" } },
new { SalYear = 2018, SalMonth = 2, C = new[] { "av2", "ao2", "aop2", "aod2" } }
};
Be like av1, av2, ao1, ao2.. so we want to sort the results first by the index of the inner array, then by the index of the outer array
We use a SelectMany to dig out the inner array and then for every item in the inner array we make a new object that has the data and the indexes (of the inner and the outer):
obj.SelectMany((theOuter, outerIdx) =>
theOuter.C.Select((theInner, innerIdx) =>
new {
SalYear = theOuter.SalYear,
SalMonth = theOuter.SalMonth,
DataItem = theInner,
OuterIdx = outerIdx,
InnerIdx = innerIdx
}
)
).OrderBy(newObj => newObj.InnerIdx).ThenBy(newObj => newObj.OuterIdx)
You will probably find you don't need the ThenBy; sorting by the InnerIdx will leave a tie (every InnerIdx in my list is represented twice -there are two innerIdx=0 etc) and things in linq sort as far as they can then no futher - because theyre sorted by OuterIdx already (when they went into the query) they should remain sorted by OuterIdx after they tie on InnerIdx.. If that makes sense. Belt and braces!
outstandingDataTotalData.Select(s => new AdjustmentTotal {
SalYear = s.SalYear,
SalMonth = s.SalMonth,
Value = s.adjustment_value
}).ToList();
Use a eum :
class Program
{
static void Main(string[] args)
{
List<AdjustmentTotal> totals = new List<AdjustmentTotal>();
for (int i = 0; i < (int)VALUE.END; i++)
{
foreach (var data in outstandingDataTotalData)
{
AdjustmentTotal total = new AdjustmentTotal();
totals.Add(total);
total.SalMonth = data.SalMonth;
total.SalYear = data.SalYear;
total._Type = (VALUE)i;
switch ((VALUE)i)
{
case VALUE.adjustment_value :
total.Value = data.adjustment_value;
break;
case VALUE.amount_outstanding:
total.Value = data.amount_outstanding;
break;
case VALUE.amount_outstanding_ded:
total.Value = data.mount_outstanding_ded;
break;
case VALUE.amount_outstanding_priv:
total.Value = data.amount_outstanding_priv;
break;
case VALUE.diff_outstanding:
total.Value = data.diff_outstanding;
break;
case VALUE.exchange_rate:
total.Value = data.exchange_rate;
break;
}
}
}
}
}
public enum VALUE
{
adjustment_value = 0,
amount_outstanding = 1,
amount_outstanding_priv = 2,
amount_outstanding_ded = 3,
diff_outstanding = 4,
exchange_rate = 5,
END = 6
}
public class AdjustmentTotal
{
public string SalYear { get; set; }
public string SalMonth { get; set; }
public string Value { get; set; }
public VALUE _Type { get; set; }
}
Below is my linq code and it works. My question is how I can "reuse" those part new ContactResponse, and new AddressResponse in a function to reuse it in another query?
var queryset = (
from a in _repoWrapper.Workshop.FindAll()
where (a.IsActive == true && a.Entity.EntityType.Code == Global.EntityTypeServiceCenterCode)
select new ServiceCenterResponse
{
Id = a.Id,
Name = a.Name,
EntityId = a.EntityId,
Contacts = a.WorkshopContacts.Select(p => new ContactResponse
{
Id = p.Contact.Id,
Type = p.Contact.ContactType.Description,
Code = p.Contact.ContactType.Code,
Value = p.Contact.Value
}).ToList(),
Addresses = a.WorkshopAddresses.Select(p => new AddressResponse
{
Id = p.Address.Id,
AddressType = p.Address.AddressType.Code,
StreetLine1 = p.Address.StreetLine1,
StreetLine2 = p.Address.StreetLine2,
City = p.Address.City,
State = p.Address.State,
PostCode = p.Address.PostCode,
Country = p.Address.Country,
Longitude = p.Address.Longitude,
Latitude = p.Address.Latitude,
Others = p.Address.Others
}).ToList()
}
);
If I correct understand your question, then try this:
Func<WorkshopContact, ContactResponse> contactResponseProjection= p => new ContactResponse
{
Id = p.Contact.Id,
Type = p.Contact.ContactType.Description,
Code = p.Contact.ContactType.Code,
Value = p.Contact.Value
};
And use:
...
Contacts = a.WorkshopContacts.Select(contactResponseProjection).ToList(),
...
Linq has a parameter of type Func in the Select method. This means that you can pass a method to it.
Let me try to do an example.
List<int> list = new List<int> { 1, 2, 3 };
list.Select(AddOne);
where AddOne is a method that you can declare and must have a parameter of type int and a return of whatever you'd like to return. eg.
public int AddOne(int value)
{
return value + 1;
}
I'm trying to write a LINQ query to get List<List<testobject>> results = ...
I get the correct results using var but want to declare the explicit type rather than use var. What is the correct syntax to do this?
Simple example is as follows
class Program
{
static void Main(string[] args)
{
List<testobject> testobjectList = new List<testobject>()
{
new testobject(){field1 = 1, field2 = "1",field3 = "1",field4 = "1", field5 = "1"},
new testobject(){field1 = 1, field2 = "1",field3 = "1a",field4 = "1a", field5 = "1a"},
new testobject(){field1 = 1, field2 = "1",field3 = "1b",field4 = "1b", field5 = "1b"},
new testobject(){field1 = 2, field2 = "2",field3 = "2",field4 = "2", field5 = "2"},
new testobject(){field1 = 3, field2 = "3",field3 = "3",field4 = "3", field5 = "3"},
new testobject(){field1 = 4, field2 = "4",field3 = "4",field4 = "4", field5 = "4"},
new testobject(){field1 = 4, field2 = "4",field3 = "4a",field4 = "4a", field5 = "4a"},
new testobject(){field1 = 5, field2 = "5",field3 = "5",field4 = "5", field5 = "5"},
new testobject(){field1 = 6, field2 = "6",field3 = "6",field4 = "6", field5 = "6"},
new testobject(){field1 = 6, field2 = "6",field3 = "6a",field4 = "6a", field5 = "6a"},
new testobject(){field1 = 6, field2 = "6",field3 = "6b",field4 = "6b", field5 = "6b"},
new testobject(){field1 = 7, field2 = "7",field3 = "7",field4 = "7", field5 = "7"}
};
// Correct output
var results1 = testobjectList.Where(x => x.field1 >= 2)
.GroupBy(x => x.field2).ToList();
// But how do I do the same but explicitly state type?
List<List<testobject>> results2 = testobjectList.Where(x => x.field1 >= 2)
.GroupBy(x => x.field2).ToList();
}
}
class testobject
{
public int field1 { get; set; }
public string field2 { get; set; }
public string field3 { get; set; }
public string field4 { get; set; }
public string field5 { get; set; }
}
First of all when you are using GroupBy function, var is compiled to:
List<IGrouping<string,testobject>>
If you really want to have List<List<testobject>> you can use this query:
testobjectList.Where(x => x.field1 >= 2).GroupBy(x => x.field2).Select(x => x.ToList()).ToList();
And if you want to have List<testobject> you can use:
testobjectList.Where(x => x.field1 >= 2).GroupBy(x => x.field2).Select(x => x.First()).ToList();
List<List<testobject>> wouldn't be the correct type. If you added a breakpoint on a line after and results1 is declared and inspected the type of it you would probably see something similar to List<IGrouping<string, testobject>>. If you want to declare explicit types use some means to figure out actual type, like a debugger, IDE or some plugin. ReSharper could give you a refactoring option to declare explicit type instead of var.
When you hover over the ToList() call in VisualStudio you can see that the return type is List<IGrouping<string, testobject>>
Try:
List<IGrouping<string, testobject>> results2 = testobjectList.Where(x => x.field1 >= 2)
.GroupBy(x => x.field2).ToList();
If you have ReSharper you can use the "Specify type explicitly" refactoring to convert the var statement to the explicit type.
You need to flatten your result by adding a .SelectMany() to strongly type the result as a List.
You also have the List declared as List<List> result 2 when it should be List
Working Sample:
List<testobject> results2 = testobjectList .Where(x => x.field1 >= 2)
.GroupBy(x=>x.field2)
.SelectMany(x=>x)
.ToList();
I have a list of "Couple" with the following structure
public class Couple
{
public string Code;
public string Label;
}
And another list of "Stuff" like that
public class Stuff
{
public string CodeStuff;
public string LabelStuff;
public int foo;
public int bar;
//etc...
}
I want to get all the Stuff objects where each couples (Code, Label) in my List<Couple> match with (CodeStuff, Label,Stuff) from List<Stuff>.
For example the Couple
Couple c = new Couple { Code = "ABC", Label = "MyLabel1" };
will match with the first row only from
Stuff s1 = new { CodeStuff = "ABC", LabelStuff = "MyLabel1" }; // OK
Stuff s1 = new { CodeStuff = "ABC", LabelStuff = "MyLabel2" }; // NOT OK
Stuff s1 = new { CodeStuff = "DEF", LabelStuff = "MyLabel1" }; // NOT OK
I tried to use .Where clause or .Foreach but I don't know how to get the couple (Code,Label) together. Can you help me ?
You need to use linq join.
List<Couple> lstcouple = new List<Couple>();
List<Stuff> lstStuff = new List<Stuff>();
var result = (from s in lstStuff
join c in lstcouple on new { CS = s.CodeStuff, LS = s.LabelStuff } equals new { CS = c.Code, LS = c.Label }
select s).ToList();
Have you tried a join? might need tweaking, but as an idea:
var joined = from c in couplesList
join s in stuffList on c.Code equals s.CodeStuff
where c.Label == s.LabelStuff
select s;
Try this:
List<Stuff> stuffs = new List<Stuff>{s1,s2,s3};
List<Couple> couples = new List<Couple>{c};
var filteredList = stuffs.
Where
(x=> couples.Any(y => y.Code == x.CodeStuff)
&& couples.Any(y=> y.Label == x.LabelStuff)
).ToList();