Entity Framework LINQ - dynamically select properties - linq

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
});

Related

what is a projection in LINQ, as in .Select()

I typically do mobile app development, which doesn't always have .Select. However, I've seen this used a bit, but I don't really know what it does or how it's doing whatever it does. It is anything like
from a in list select a // a.Property // new Thing { a.Property}
I'm asking because when I've seen code using .Select(), I was a bit confused by what it was doing.
.Select() is from method syntax for LINQ, select in your code from a in list select a is for query syntax. Both are same, query syntax compiles into method syntax.
You may see: Query Syntax and Method Syntax in LINQ (C#)
Projection:
Projection Operations - MSDN
Projection refers to the operation of transforming an object into a
new form that often consists only of those properties that will be
subsequently used. By using projection, you can construct a new type
that is built from each object. You can project a property and perform
a mathematical function on it. You can also project the original
object without changing it.
You may also see:
LINQ Projection
The process of transforming the results of a query is called
projection. You can project the results of a query after any filters
have been applied to change the type of the collection that is
returned.
Example from MSDN
List<string> words = new List<string>() { "an", "apple", "a", "day" };
var query = from word in words
select word.Substring(0, 1);
In the above example only first character from each string instance is selected / projected.
You can also select some fields from your collection and create an anonymous type or an instance of existing class, that process is called projection.
from a in list select new { ID = a.Id}
In the above code field Id is projected into an anonymous type ignoring other fields. Consider that your list has an object of type MyClass defined like:
class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Now you can project the Id and Name to an anonymous type like:
Query Syntax:
var result = from a in list
select new
{
ID = a.Id,
Name = a.Name,
};
Method Syntax
var result = list.Select(r => new { ID = r.Id, Name = r.Name });
You can also project result to a new class. Consider you have a class like:
class TemporaryHolderClass
{
public int Id { get; set; }
public string Name { get; set; }
}
Then you can do:
Query Syntax:
var result = from a in list
select new TemporaryHolderClass
{
Id = a.Id,
Name = a.Name,
};
Method Syntax:
var result = list.Select(r => new TemporaryHolderClass
{
Id = r.Id,
Name = r.Name
});
You can also project to the same class, provided you are not trying to project to classes generated/created for LINQ to SQL or Entity Framework.
My summary is it takes results (or a subset of results) and allows you to quickly restructure it for use in the local context.
The select clause produces the results of the query and specifies the
"shape" or type of each returned element. For example, you can specify
whether your results will consist of complete Customer objects, just
one member, a subset of members, or some completely different result
type based on a computation or new object creation.
Source: http://msdn.microsoft.com/en-us/library/bb397927.aspx
There are a lot of possible uses for this but one is taking a complex object which of many other contains a property that is a string -- say Name -- and allows you to return an enumeration with just the entries of Name. I believe you can also do the opposite -- use that property ( for example) and create / return new type of object while passing in a property or properties.
It means "mapping". Map each element of a sequence to a transformed sequence. I hadn't comprehended its meaning before I looked at the image.
Where does the meaning of the word come from?
Simply, math! https://mathworld.wolfram.com/Projection.html

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

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).

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.

IN and NOT IN with Linq to Entities (EF4.0)

This has been ruining my life for a few days now, time to ask...
I am using Entity Framework 4.0 for my app.
A Location (such as a house or office) has one or more facilities (like a bathroom, bedroom, snooker table etc..)
I want to display a checkbox list on the location page, with a checkbox list of facilities, with the ones checked that the location currently has.
My View Model for the facilities goes like this...
public class FacilityViewItem
{
public int Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
So when im passing the Location View Model to the UI, i want to pass a List<T> of facilities where T is of type FacilityViewItem.
To get the facilities that the location already has is simple - i make a query using Location.Facilities which returns an EntityCollection where T is of type Facility. This is because Facilities is a navigation property....
var facs = from f in location.Facilities
select new FacilityViewItem()
{
Id = f.FacilityId,
Name = f.Name,
Checked = true
};
So here is where my problem lies - i want the rest of the facilities, the ones that the Location does not have.
I have tried using Except() and Any() and Contains() but i get the same error.
Examples of queries that do not work...
var restOfFacilities = from f in ctx.Facilities
where !hasFacilities.Contains(f)
select new FacilityViewItem()
{
Id = f.FacilityId,
Name = f.Name
};
var restOfFacilities = ctx.Facilities.Except(facilitiesThatLocationHas);
var notFacs = from e in ctx.Facilities
where !hasFacilities.Any(m => m.FacilityId == e.FacilityId)
select new FacilityViewItem()
{
Id = e.FacilityId,
Name = e.Name
};
And the error i get with every implementation...
System.NotSupportedException was unhandled
Message=Unable to create a constant value of type 'Chapter2ConsoleApp.Facility'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
What am i overlooking here?
ironically enough i solved it in a matter of hours after i posted the question on here, after days of suffering.
The error is basically saying 'i dont know how to calculate what items are not included by comparing strongly typed objects. Give me a list of Ints or some simple types, and i can take care of it'.
So, first you need to get a list of the primary keys, then use that in the contains clause...
//get the primary key ids...
var hasFacilityIds = from f in hasFacilities
select f.FacilityId;
//now use them in the contains clause...
var restOfFacilities = from f in ctx.Facilities
where !hasFacilityIds.Contains(f.FacilityId)
select new FacilityViewItem()
{
Id = f.FacilityId,
Name = f.Name
};
The first query seems fine, but you need to compare the Ids:
var restOfFacilities = from f in ctx.Facilities
where !facs.Select(fac => fac.Id).Contains(f.Id)
select f;
I wanna see what's hasFacilities, anyway, as L2E shows, "Only primitive types ('such as Int32, String, and Guid') are supported in this context", so I suppose you must retrieve first the data and put into a collection of FacilityViewItem.
var restOfFacilities = ctx
.Facilities
.Where(f => !hasFacilities.Contains(f))
.Select(f => new { f.FacilityId, f.Name })
.ToList()
.Select(f => new FacilityViewItem {
Id = f.FacilityId,
Name = f.Name
});
var notFacs = ctx
.Facilities
.Where(e => !hasFacilities.Any(m => m.FacilityId == e.FacilityId))
.Select(e => new { e.FacilityId, e.Name })
.ToList()
.Select(e => new FacilityViewItem {
Id = e.FacilityId,
Name = e.Name
});
hope it helps

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

Resources