Returning Linq query results into a List object (based on condition) - linq

I need to return a number of Linq query results into a List object based on a foreign key value. What is the syntax for doing this? I am new to using Linq, so below is my best guess so far. I receive an error in the .Where() "clause" stating "The name 'pt' does not exist in the current context. Any help would be greatly appreciated!
List<AgentProductTraining> productTraining = new List<AgentProductTraining>();
var prodCodes = productTraining.Select(pt => new[]
{
pt.ProductCode,
pt.NoteId,
pt.ControlId
})
.Where(pt.CourseCode == course.CourseCode);

You would need to switch the locations of where and select if you're using extension methods:
var prodCodes = productTraining.Where(pt => pt.CourseCode == course.CourseCode)
.Select(pt => new SomeRandomType
{
ProductCode = pt.ProductCode,
NoteId = pt.NoteId,
ControlId = pt.ControlId
});
I also recommend, as you can see above, that you create a type for that select statement so that you're not relying on anonymous types. You should put in into an object type that you know everything about.
Also, if CourseCode is a string, that should be pt.CourseCode.Equals(course.CourseCode).

Related

Entity Framework LINQ - dynamically select properties

Is it possible to create a dynamic selector like the below one in a simple way, and how?
Func<Company, string> companyName = x.CompanyName;
Func<Company, int> companyId = x.CompanyId;
var result = datacontext.Select(x => new
{
CompanyName = companyName,
CompanyId = companyId
});
The above code throws exception: "Unable to create a constant value of type 'System.Func`2... ...Only primitive types or enumeration types are supported in this context."
The problem is that I need to dynamically select up to 8 fields out of possible 50 from approximately 10 different tables, and these fields can be of types string, int, datetime nullable and not nullable. It is quiet difficult to dynamically construct a selector with Expressions. What is the best way to tackle this?
var result = datacontext.Select(x => new
{
CompanyName = mcname(x),
CompanyId = companyId(x)
});
But where is the reason?
Your Funcs should look like this:
Func<Company, string> companyName = (company => company.CompanyName);
Func<Company, int> companyId = (company => company.CompanyId);
To use your func:
var result = datacontext.Select(x => new
{
CompanyName = companyName(x),
CompanyId = companyId(x)
});
I don't know of a way to dynamically create a query for specific fields. You can dynamically chain filters with a single execution though... Unless you're storing a significant amount of information on each row or are loading hundreds of thousands of rows I wouldn't worry about it.
P.S. You'll want to be careful using custom functions in your primary database filters. LINQ can't translate all commands to a native SQL query so it may end up pulling an entire table and filtering in within your code. Just pay attention.
I'm not exactly sure what you are trying to accomplish, but could what you want be done simply like this?
var result = datacontext.Select(x => new
{
CompanyName = x.companyName,
CompanyId = x.companyId
});

LINQ ForEach with Replace

I am trying to replace a string date value "01/01/1700" with an empty string in LINQ.
The date is of type string.
Something like this but I cant get it to work.
Query<Client>(sql).ToList().ForEach(x => x.DateOfBirth =
x.DateOfBirth.Replace("01/01/1700", ""));
This code works but its not LINQ.
var result = Query<Client>(sql).ToList();
foreach (var client in result)
{
if (client.DateOfBirth == "01/01/1700")
{
client.DateOfBirth = "n/a";
}
}
Thanks for your help.
The problem is the ToList(). The result is not visible in the variable you use afterwards.
Try out the following:
var list = Query<Client>(sql).ToList();
list.ForEach(l => l.DateOfBirth = l.DateOfBirth.Replace("01/01/1700", "n/a"));
Should work fine. Use the list variable afterwards.
var result = Query<Client>(sql).ToList();
result.ForEach(l => l.DateOfBirth = l.DateOfBirth.Replace("01/01/1700", "n/a"));
Your code assumes that changes made to an object in a List will be reflected in the Query<Client> that the object came from. Apparently this is not the case. One thing you could try is assigning the list before calling ForEach() and using the list from that point on:
var clients = Query<Client>(sql).ToList();
clients.ForEach(x => x.DateOfBirth = x.DateOfBirth.Replace("01/01/1700", ""));
Also, ForEach is not a LINQ operator. It is a method in the List class. Unlike LINQ operators, it will modify the list that called it and will not return anything. The way to "modify" data with LINQ is by using select:
var clients = (from client in Query<Client>(sql).ToList()
select new Client(client)
{
DateOfBirth = client.DateOfBirth.Replace("01/01/1700", "")
}).ToList();

LINQ to Entities does not recognize the method 'Boolean CheckMeetingSettings(Int64, Int64)' method

I am working with code first approach in EDM and facing an error for which I can't the solution.Pls help me
LINQ to Entities does not recognize the method 'Boolean
CheckMeetingSettings(Int64, Int64)' method, and this method cannot be
translated into a store expression.
My code is following(this is the query which I have written
from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
}
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
Please help me out of this.
EF can not convert custom code to SQL. Try iterating the result set and assigning the property outside the LINQ query.
var people = (from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
order by /**/
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
}).Skip(/*records count to skip*/)
.Take(/*records count to retrieve*/)
.ToList();
people.ForEach(p => p.CanSendMeetingRequest = CheckMeetingSettings(6327, p.Id));
With Entity Framework, you cannot mix code that runs on the database server with code that runs inside the application. The only way you could write a query like this, is if you defined a function inside SQL Server to implement the code that you've written.
More information on how to expose that function to LINQ to Entities can be found here.
Alternatively, you would have to call CheckMeetingSettings outside the initial query, as Eranga demonstrated.
Try:
var personDetails = obj.tempPersonConferenceDbSet.Where(p=>p.ConferenceId == 2).AsEnumerable().Select(p=> new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
});
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
You must use AsEnumerable() so you can preform CheckMeetingSettings.
Linq to Entities can't translate your custom code into a SQL query.
You might consider first selecting only the database columns, then add a .ToList() to force the query to resolve. After you have those results you van do another select where you add the information from your CheckMeetingSettings method.
I'm more comfortable with the fluid syntax so I've used that in the following example.
var query = obj.tempPersonConferenceDbSet
.Where(per => per.Conference.Id == 2).Select(per => new { Id = per.Person.Id, JobTitle = per.Person.JobTitle })
.ToList()
.Select(per => new PersonDetails { Id = per.Id,
JobTitle = per.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327, per.Person.Id) })
If your CheckMeetingSettings method also accesses the database you might want to consider not using a seperate method to prevent a SELECT N+1 scenario and try to express the logic as part of the query in terms that the database can understand.

Create new Linq SelectMany extension method

I am using Linq.Dynamic. I have already added another SelectMany extension to all for creating a new anonymous object with the data. But, I have ran into another issue that I can not seem to solve.
I want to have extension method chaining as follows, but using the dynamic methods:
var customerandorderflat = db.Customers
.SelectMany(c => c.Orders.SelectMany(o => o.Order_Details,
(ord, orddetail) => new
{
OrderID = ord.OrderID,
UnitPrice = orddetail.UnitPrice
}).DefaultIfEmpty(),
(cus, ord) => new
{
CustomerId = cus.CustomerID,
CompanyName = cus.CompanyName,
OrderId = ord.OrderID == null ? -1 : ord.OrderID,
UnitPrice = ord.UnitPrice
});
Ideally I would like to chain the dynamic SelectMany as follows:
db.Customers.SelectMany(c => c.Orders.SelectMany("Order_Details", "new(outer.OrderID, inner.UnitPrice)"), "new(outer.CustomerID, inner.OrderID)");
Or something to that affect. The problem is that I can not get a signature to match.
I have tried many different options to get it to allow chaining. But it just doesn't work. I am thinking ideally it would look like this:
public static IQueryable SelectMany(this IQueryable source, IQueryable innerExpression, string resultsSelector, params object[] values)
But, it doesn't recognize c => c.Orders as IQueriable. I also need to figure out how to do DefaultIfEmpty on the results to allow for LEFT JOINs.
Please help.
c.Orders is an EntitySet. EntitySet doesn't implement IQueryable. Try c.Orders.AsQueryable()
It was getting the wrong definition. Actual error when on right definition: Cannot convert lambda expression to type 'System.Linq.IQueryable' because it is not a delegate type

linq help - newbie

how come this work
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == 1
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
but this does not
public IQueryable<Category> getCategories(int postId)
{
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
var query = from c in categories.GetAll()
join pcm in postCategoryMap.GetAll() on c.CategoryId equals pcm.CategoryId
where pcm.PostId == postId
select new Category
{
Name = c.Name,
CategoryId = c.CategoryId
};
return query;
}
The issue is most likely in the implementation of the query provider.
pcm.PostId == 1
and
pcm.PostId == postId
actually have a big difference. In the expression tree the first is generated as a ConstantExpression which doesnt need to be evaulated.
With the second, the compiler actually generates an inner class here (this is the _DisplayClassX that you see). This class will have a property (will most likely be the same name as your parameter) and the expression tree will create a MemberAccessExpression which points to the auto-generated DisplayClassX. When you query provider comes accross this you need to Compile() the Lambda expression and evaluate the delegate to get the value to use in your query.
Hope this helps.
cosullivan
The problem is not the linq itself,
you need to be sure that the context or provider object is able to fetch the data.
try testing the
subnusMVCRepository<Categories> categories = new subnusMVCRepository<Categories>();
subnusMVCRepository<Post_Category_Map> postCategoryMap = new subnusMVCRepository<Post_Category_Map>();
objects and see if they are populated or if they behaving as required.
you may want to search the generated code for c__DisplayClass1 and see what you can see there. some times the generated code dose some weird things.
when you step into you code check the locals and the variable values. this may also give you some clues.
Edit : Have you tried to return a List<> collection ? or an Enumerable type?
Edit : What is the real type of the item and query may not be iterable

Resources