I want to declare empty variable for this condition,
if(........)
{
emptyIQueryable= DBContext.MyTables.Join(MyTableTwos , x => x.ID , i => i.TID , ((x,i) =>
new{
x,i
}
)).Where(x => x.ID == 1).SingleOrDefault();
}
else
{
emptyIQueryable= DBContext.MyTables.Join(MyTableTwos , x => x.ID , i => i.TID , ((x,i) =>
new{
x,i
}
)).Where(x => x.ID == 2).SingleOrDefault();
}
How can I declare it ?
SingleOrDefault does not return an IQueryable - it returns the object that MyTables consists of, or null. So if MyTables contains several objects of type say MyTable, that is the type for your variable:
MyTable result;
if(........)
{
result = DBContext.MyTables.SingleOrDefault(x => x.ID == 1);
}
else
{
result = DBContext.MyTables.SingleOrDefault(x => x.ID == 2);
}
Update. After edit thing get more complicated. The expression you are using returns object of type IEnumerable<anonymous>, which is impossible to state in code explicitly. You can, however, use either object or IEnumerable for emptyIQueryable, but you will loose some info about the object either way.
However this code can be easily refactored to get rid of the problem completely:
Func<MyTable, bool> condition;
if (.....)
{
condition = x => x.ID == 1;
}
else
{
condition = x => x.ID == 2;
}
var emptyIQueryable =
DBContext.MyTables
.Join(MyTableTwos, x => x.ID, i => i.TID, ((x,i) => new {x,i}))
.Where(condition).SingleOrDefault();
It is possible to declare a variable as being an anonymous type without assigning to it. It's kind of a trick of the compiler, but you can do it like this.
var emptyIQueryable = false
? new { x = default(MyTable), i = default(MyTableTwo) }
: null;
emptyIQueryable is assigned to null, and that anonymous object is never constructed. But it has the exact some IL type as you create later. The compiler guarantees that any two anonymously typed objects created in the same method that have the same properties with the same types in the same order will have the same type. Therefore, you could assign to it in your if block later.
Related
I have the following statement.
List<ApplicationUserDto> peers = _context.ApplicationUsers
.Select(m => new ApplicationUserDto
{
Id = m.Id,
MyCount = m.GroupMemberships
.Count(pg => pg.StudentGroup.ReviewRoundId == reviewRoundId)
}).ToList();
I have another class, called PeerStudentGroup derived from StudentGroup. In the Count() function, I do not want them to be included. I mean I want to count only if it is StudentGroup type (not another class derived from it). I wonder how I can achieve this. Any suggestions?
In this case you can use the is keyword which compares instance types. You should add !(pg.StudentGroup is PeerStudentGroup) to your condition.
Your code should look like this:
List<ApplicationUserDto> peers = _context.ApplicationUsers
.Select(m => new ApplicationUserDto
{
Id = m.Id,
MyCount = m.GroupMemberships
.Count(pg => pg.StudentGroup.ReviewRoundId == reviewRoundId && !(pg.StudentGroup is PeerStudentGroup))
}).ToList();
This might help to start with:
Apply a .Where (filtering) statement before the projection (Select) like
MyCount = m.GroupMemberships
.Where(gm => !(gm is PeerStudentGroup))
[alternatively] typeof(gm) != typeof(PeerStudentGroup)
.Count(pg => pg.StudentGroup.ReviewRoundId == reviewRoundId)
I'm trying to pass lambda expressions and a type to my DAL. I have this statement:
(entities).GetType().GetMethod("Where")
"entities" is the Table of entities on the DataContext.
When I run the statement I get a null even though Linq.Table inherits IQueryable.
Anyone have an idea?
Here is the entire method:
public object GetResultSet(Dictionary<Type, Func<object, bool>> values)
{
using (ICSDataContext db = DataContextFactory.CreateDataContext<ICSDataContext>(DataContexts.ICS))
{
foreach (var entry in values)
{
var property = db.GetType().GetProperty(entry.Key.Name + "s");
IQueryable entities = (IQueryable)property.GetValue(db, null);
var whereMethod = (entities).GetType().GetMethod("Where")
.MakeGenericMethod(Type.GetType(entry.Key.AssemblyQualifiedName));
return whereMethod.Invoke(entities, new object[] { entry.Value });
}
}
return null;
}
Thanks
As an alternative you could do something like
db.Set<Type>()
which will return you the DBSet of the appropriate type, with Where accessible without reflection. Also you may want to use Expression> rather than Func, expressions work on queryables where as funcs work on enumerables. If you pass a func into a Where clause it pulls the entire dbset down and processes it in memory.
Typed expressions are also a little easier to work with (intellesence, type checking).
Expression<Func<User,bool>> filter = c=>c.FirstName == "Bob";
As another alternative you can look into System.Linq.Dynamic, ScottGu has a write up on it here. The article and the code are old, but it works with EF 6. It allows things like
.Where("CategoryId=2 and UnitPrice>3")
From answer by LukeH under here:
var where1 = typeof(Queryable).GetMethods()
.Where(x => x.Name == "Where")
.Select(x => new { M = x, P = x.GetParameters() })
.Where(x => x.P.Length == 2
&& x.P[0].ParameterType.IsGenericType
&& x.P[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>)
&& x.P[1].ParameterType.IsGenericType
&& x.P[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>))
.Select(x => new { x.M, A = x.P[1].ParameterType.GetGenericArguments() })
.Where(x => x.A[0].IsGenericType
&& x.A[0].GetGenericTypeDefinition() == typeof(Func<,>))
.Select(x => new { x.M, A = x.A[0].GetGenericArguments() })
.Where(x => x.A[0].IsGenericParameter
&& x.A[1] == typeof(bool))
.Select(x => x.M)
.SingleOrDefault();
Then this:
var gmi = where1.MakeGenericMethod(typeof(T));
What is the correct return data type for an AnonymousType#1?
This code is working.
var c = p.IQueryableGetAll()
.Where(r => r.Gender == "M")
.Select(r => new { r.FirstName, r.LastName })
.ToList();
But when I placed it inside a function, error occurs.
public List<object> GetFirstNameAndLastNameOfMales()
{
var p = new Program();
return p.IQueryableGetAll()
.Where(r => r.Gender == "M")
.Select(r => new { r.FirstName, r.LastName })
.ToList();
}
Here's the error
Cannot implicitly convert type
System.Collections.Generic.List<AnonymousType#1> to
System.Collections.Generic.List<object>
How is it done correctly? Thank you.
You query in both cases is correct. However that causes the problem in the second case is the return type of your method.
You could try this one:
return p.IQueryableGetAll()
.Where(r => r.Gender == "M")
.Select(r => new { r.FirstName, r.LastName }).ToList<Object>();
The reason why you are getting this error is because
Select(r => new { r.FirstName, r.LastName })
select an anonymous type for each element in the sequence that has Gender==M. An the .ToList() at the end of your query creates a List of objects that have as their type this anonymnous type with these two properties.
A better option would be to create a class that will hold these two properties, let's call it Customer and then do the following:
public List<Customer> GetFirstNameAndLastNameOfMales()
{
var p = new Program();
return p.IQueryableGetAll()
.Where(r => r.Gender == "M")
.Select(r => new Customer {
FirstName = r.FirstName,
LastName = r.LastName
}).ToList();
}
It doesn't work because List<T> is not covariant - it is a list of a specific type, so you can't add any object to it. You can either:
Create a concrete type and use it
Cast your result to object :
.Select(r => (object)(new { r.FirstName, r.LastName }))
change the return type to IEnumerable<object> which is covariant (since you can't add to it)
Option 1 is the cleanest but requires additional code - options 2 and 3 are easy on the query side but require reflection or dynamic on the client side (and run-time vulnerability, and lack of compile-time safety, etc.).
About the homework:
There are casters(witch(0)/fairy(1)) and they have spellpower(int). I stored them in a list.
I'm to find the best of both types. (There can be multiple casters with the same spellpower)
I've come up with this code, but there is a problem. If the caster with the most spellpower is a 1, then the first FindAll won't return anything, because it tries to find the caster with type 0 AND with the most spellpower. How can I get a list containing type 0 caster(s) with the most spellpower, if the caster with the most overall spellpower is type 1?
private List<Caster> BestCasters()
{
List<Caster> temp = new List<Caster>();
temp = casters.FindAll(x => x.SpellPower == casters.Max(y => y.SpellPower) && (x.TypeOfCaster == 0));
temp.AddRange(casters.FindAll(x => x.SpellPower == casters.Max(y => y.SpellPower) && (x.TypeOfCaster == 1)));
temp.OrderBy(x => x.TypeOfCaster).ThenBy(y => y.CasterName);
return temp;
}
The LINQ GroupBy behavior is perfect for this:
var strongest_casters = casters.GroupBy(c => c.TypeOfCaster)
.Select(grp => grp.OrderByDescending(x => x.SpellPower)
.First()
);
Or to return more than one of each type:
var strongest_casters = casters.GroupBy(c => c.TypeOfCaster)
.SelectMany(grp => grp.Where(y.SpellPower == grp.Max(x => x.SpellPower))
);
private List<Caster> BestCasters()
{
var witches = casters.Where(x => x.TypeOfCaster == 0).ToList();
var fairies = casters.Where(x => x.TypeOfCaster == 1).ToList();
int witchesMax = witches.Max(x => x.SpellPower);
int fairiesMax = fairies.Max(x => x.SpellPower);
var temp = witches.Where(x => x.SpellPower == witchesMax).ToList();
temp.AddRange(fairies.Where(x => x.SpellPower == fairiesMax));
return temp.OrderBy(x => x.TypeOfCaster).ThenBy(y => y.CasterName).ToList();
}
If you have to use FindAll like this you should invoke the Max on a subset only containing the casters of the right kind. Of course it would make more sense to split the initial list first and then fetch the strongest caster of each kind.
Since you did not tell what exactly you have to do I can only hope that you are allowed to split :-)
I have this search method:
public List<Employeees> AutoSuggestEmployeee(string keyword,
long employeeeTypeId, int count)
{
return context.Employeees.Where(
x => x.EmployeeeName.Contains(keyword)
&& x.EmployeeeTypeId == employeeeTypeId)
.Take(count).ToList();
}
I have another collection of Employeees, say "BadEmployeees", what I want is using the same previous method to return all Employeees except "BadEmployeees".
I tried to write it like this:
return context.Employeees.Where(
x => x.EmployeeeName.Contains(keyword)
&& x.EmployeeeTypeId == employeeeTypeId)
.Except(BadEmployeees).Take(count).ToList();
But it is giving an exception that Except can just work with data types such as Int, Guid,...
The Except method does a comparison, so it has to know how to compare the objects. For simple types there are standard comparisons, but for complex types you need to supply an equality comparer that compares the relevant data in the object.
Example:
class EmployeeComparer : IEqualityComparer<Employeees> {
public bool Equals(Employeees x, Employeees y) {
return x.Id == y.Id;
}
public int GetHashCode(Employeees employee) {
return employee.Id.GetHashCode();
}
}
Usage:
return
context.Employeees
.Where(x => x.EmployeeeName.Contains(keyword) && x.EmployeeeTypeId == employeeeTypeId)
.Except(BadEmployeees, new EmployeeComparer())
.Take(count)
.ToList();
If you're happy to retrieve all the data and then perform the "except", that's relatively easy:
return context.Employees
.Where(x => x.EmployeeName.Contains(keyword)
&& x.EmployeeTypeId == employeeeTypeId)
// Limit the data *somewhat*
.Take(count + BadEmployees.Count)
// Do the rest of the query in-process
.AsEnumerable()
.Except(BadEmployees)
.Take(count)
.ToList();
Alternatively:
// I'm making some assumptions about property names here...
var badEmployeeIds = badEmployees.Select(x => x.EmployeeId)
.ToList();
return context.Employees
.Where(x => x.EmployeeName.Contains(keyword)
&& x.EmployeeTypeId == employeeeTypeId)
&& !badEmployeeIds.Contains(x.EmployeeId))
.Take(count)
.ToList();