Linq to Entities exception - linq

Hi I have a query like this:
var queryGridData = from question in questions
select new {
i = question.Id,
cell = new List<string>() { question.Id.ToString(), question.Note, question.Topic }
};
The ToString() part needed to convert the int is causing:
LINQ to Entities does not recognize the method 'System.String.ToString()' method, and this method cannot be translated into a store expression.
Hmmmmmmmmmmm. I need it as a string to go into the collection. Any ideas?

I would personally perform just enough of the query in the database to provide the values you want, and do the rest in .NET:
var queryGridData = questions.Select(q => new { q.Id, q.Note, q.Topic })
.AsEnumerable() // Do the rest locally
.Select(q => new { i = q.Id,
cell = new List<string> {
q.Id.ToString(),
q.Note,
q.Topic
} });
(This formatting is horrible, but hopefully it'll be easier to do nicely in an IDE where you've got more space :)

Related

How can i construct a NEST query with optional parameters?

I'm using the NEST .NET client (6.3.1), and trying to compose a search query that is based on a number of (optional) parameters.
Here's what i've got so far:
var searchResponse = await _client.SearchAsync<Listing>(s => s
.Query(qq =>
{
var filters = new List<QueryContainer>();
if (filter.CategoryType.HasValue)
{
filters.Add(qq.Term(p => p.CategoryType, filter.CategoryType.Value));
}
if (filter.StatusType.HasValue)
{
filters.Add(qq.Term(p => p.StatusType, filter.StatusType.Value));
}
if (!string.IsNullOrWhiteSpace(filter.Suburb))
{
filters.Add(qq.Term(p => p.Suburb, filter.Suburb));
}
return ?????; // what do i do her?
})
);
filter is an object with a bunch of nullable properties. So, whatever has a value i want to add as a match query.
So, to achieve that i'm trying to build up a list of QueryContainer's (not sure that's the right way), but struggling to figure out how to return that as a list of AND predicates.
Any ideas?
Thanks
Ended up doing it by using the object initialisez method, instead of the Fluent DSL"
var searchRequest = new SearchRequest<Listing>
{
Query = queries
}
queries is a List<QueryContainer>, which i just build up, like this:
queries.Add(new MatchQuery
{
Field = "CategoryType",
Query = filter.CategoryType
}
I feel like there's a better way, and i don't like how i have to hardcode the 'Field' to a string... but it works. Hopefully someone shows me a better way!

Custom IComparer in LINQ OrderBy Lambda expression

I have a custom comparer I want to use with OrderBy. I am trying to build a LINQ expression to make it work. So in essence, I am trying to put together an IComparer, OrderBy inLinq expression.
The expression I am trying to build should look something like:
source => source.OrderBy(lambdaParameter => lambdaParameter.Name, new Parsers.NumericComparer()).
With the code below the expression
'{source => source.OrderBy(lambdaParameter => lambdaParameter.Name)}'
is built and I am trying to add this custom Icomparable to this expression
new Parsers.NumericComparer().
This is because I need to do a natural sort. Can someone please help me on how to include this expression. I am trying to read several threads for the past few hours but I have not done understood LINQ expressions well enough yet to implement this. Thanks!
private void CreateOrderByMethod(PropertyDescriptor prop, string orderByMethodName, string cacheKey)
{
/*
Create a generic method implementation for IEnumerable<T>.
Cache it.
*/
var sourceParameter = Expression.Parameter(typeof(List<T>), "source");
var lambdaParameter = Expression.Parameter(typeof(T), "lambdaParameter");
var accesedMember = typeof(T).GetProperty(prop.Name);
var propertySelectorLambda =
Expression.Lambda(Expression.MakeMemberAccess(lambdaParameter, accesedMember), lambdaParameter);
var orderByMethod = typeof(Enumerable).GetMethods()
.Where(a => a.Name == orderByMethodName &&
a.GetParameters().Length == 2)
.Single()
.MakeGenericMethod(typeof(T), prop.PropertyType);
var orderByExpression = Expression.Lambda<Func<List<T>, IEnumerable<T>>>(
Expression.Call(orderByMethod,
new Expression[] { sourceParameter,
propertySelectorLambda }),
sourceParameter);
cachedOrderByExpressions.Add(cacheKey, orderByExpression.Compile());
}
To create an expression that creates a new instance of an object, use Expression.New.
var newParser = Expression.New(typeof(Parsers.NumericComparer));
Then I suggest you use this overload of Expression.Call instead, so that you don't have to go and manually grab the MethodInfo:
var orderByCall = Expression.Call(
typeof(Enumerable),
"OrderBy",
new [] { typeof(T), prop.PropertyType },
sourceParameter, propertySelectorLambda, newParser);

linq: Using methods in select clause

I'm breaking my head with this and decided to share my problem with you
I want to create an anonymous select from several tables, some of them may contain more than one result. i want to concatenate these results into one string
i did something like this:
var resultTable = from item in dc.table
select new
{
id= item.id,
name= CreateString((from name in item.Ref_Items_Names
select name.Name).ToList()),
};
and the CreateString() is:
private string CreateString(List<string> list)
{
StringBuilder stringedData = new StringBuilder();
for (int i = 0; i < list.Count; i++)
{
stringedData.Append(list[i] + ", ");
}
return stringedData.ToString();
}
my intentions were to convert the "name" query to list and then sent it to CreateString() to convert it to one long concatenated string.
I tried using .Aggregate((current,next) => current + "," + next);
but when i try to convert my query to DataTable like below:
public DataTable ToDataTable(Object query)
{
DataTable dt = new DataTable();
IDbCommand cmd = dc.GetCommand(query as IQueryable);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = (SqlCommand)cmd;
cmd.Connection.Open();
adapter.Fill(dt);
cmd.Connection.Close();
return dt;
}
I'm getting exception that "dc.GetCommand()" can't understand query with Aggregate method
later I tried to even use this simple query:
var resultTable = from itemin dc.table
select new
{
name = CreateString()
};
When CreateString() returns "success", nothing was inserted to "name"
why there is no way of using methods in select clause?
Thank you
Yotam
There is difference between LINQ to objects and LINQ to some-db-provider. Generally speaking, when using IQueryable, you can't use any methods, except the ones your provider understands.
What you can do is to retrieve the data from the database and then do the formatting using LINQ to objects:
var data = from item in dc.table
where /* some condition */
select item;
var result = from item in data.AsEnumerable()
select new
{
name = SomeFunction(item)
}
The AsEnumerable() extension method forces processing using LINQ to objects.
Forgive me if I've miss interpreted your question. It seems that what you are trying to do is abstract your select method for reuse. If this is the case, you may consider projection using a lambda expression. For example:
internal static class MyProjectors
{
internal static Expression<Func<Object1, ReturnObject>> StringDataProjector
{
get
{
return d => new Object1()
{
//assignment here
}
}
}
}
Now you can select your datasets as such:
dc.Table.Select(MyProjectors.StringDataProjector)
As for the concatenation logic, what about selecting to some base class with an IEnumerable<string> property and a read-only property to handle the concatenation of the string?

WCF Data Services + LINQ Projection into a custom type

I'm trying to project parts of a Display and its list of locations from a WCF Data service into a custom type. Is this doable in WCF Data Services in a Silverlight client? There is some help here, but it doesn't show getting a list back as well as simple strings.
Currently I'm getting "NotSupportedException: Constructing or initializing instances of the type UserQuery+Info with the expression d.Base.Title is not supported.".
It would be a bonus if you could tell me how to do Expand on Locations in this syntax (I know about Displays.Expand("Locations")) or if I need it.
LINQPad snippet
var displays = from d in Displays.Where(d => d.Id == 3136)
select new Info
{
Name = d.Base.Title,
};
displays.Dump();
}
public class Info
{
private string name;
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
public IEnumerable<Location> locations;
public IEnumerable<Location> Locations
{
get{ return this.locations;}
set{ this.locations = value;}
}
The problem is that you are effectively asking your WCF server to construct some type it has no knowledge about. Since it is unable to do so, you have to it yourself on your computer:
Displays
.Where(d => d.Id == 3136)
.AsEnumerable()
.Select(d => new Info { Name = d.Base.Title })
This will run the Where() on the server, but the Select() on your computer.
As already noted by svick you can't ask the server for types it doesn't understand (at least not using OData that is). But you can still only ask for properties you want and nothing more.
Since I don't have your service available the below sample uses the demo service on odata.org:
DemoService ctx = new DemoService(new Uri("http://services.odata.org/OData/OData.svc/"));
var q =
ctx.Products
.Where(p => p.ID == 1)
.Select(p =>
new Product
{
Category = new Category
{
Name = p.Category.Name
}
});
var r =
q.AsEnumerable()
.Select(p =>
new
{
CategoryName = p.Category.Name
});
The first query "q" will run compoletely on server (except for creation of the client side objects) and it will only get the Name of the category (and metadata about all the entities in question). It will translate to URL like /Products(1)?$expand=Category&$select=Category/Name.
The second query starts with the AsEnumerable, which effectively executes the first query and then it just performs a simple transform into an anonymous type. This is done completely on the client (no server interaction).

How can I create an Expression within another Expression?

Forgive me if this has been asked already. I've only just started using LINQ. I have the following Expression:
public static Expression<Func<TblCustomer, CustomerSummary>> SelectToSummary()
{
return m => (new CustomerSummary()
{
ID = m.ID,
CustomerName = m.CustomerName,
LastSalesContact = // This is a Person entity, no idea how to create it
});
}
I want to be able to populate LastSalesContact, which is a Person entity.
The details that I wish to populate come from m.LatestPerson, so how can I map over the fields from m.LatestPerson to LastSalesContact. I want the mapping to be re-useable, i.e. I do not want to do this:
LastSalesContact = new Person()
{
// Etc
}
Can I use a static Expression, such as this:
public static Expression<Func<TblUser, User>> SelectToUser()
{
return x => (new User()
{
// Populate
});
}
UPDATE:
This is what I need to do:
return m => (new CustomerSummary()
{
ID = m.ID,
CustomerName = m.CustomerName,
LastSalesContact = new Person()
{
PersonId = m.LatestPerson.PersonId,
PersonName = m.LatestPerson.PersonName,
Company = new Company()
{
CompanyId = m.LatestPerson.Company.CompanyId,
etc
}
}
});
But I will be re-using the Person() creation in about 10-15 different classes, so I don't want exactly the same code duplicated X amount of times. I'd probably also want to do the same for Company.
Can't you just use automapper for that?
public static Expression<Func<TblCustomer, CustomerSummary>> SelectToSummary()
{
return m => Mapper.Map<TblCustomer, CustommerSummary>(m);
}
You'd have to do some bootstrapping, but then it's very reusable.
UPDATE:
I may not be getting something, but what it the purpose of this function? If you just want to map one or collection of Tbl object to other objects, why have the expression?
You could just have something like this:
var customers = _customerRepository.GetAll(); // returns IEnumerable<TblCustomer>
var summaries = Mapper.Map<IEnumerable<TblCustomer>, IEnumerable<CustomerSummary>>(customers);
Or is there something I missed?
I don't think you'll be able to use a lambda expression to do this... you'll need to build up the expression tree by hand using the factory methods in Expression. It's unlikely to be pleasant, to be honest.
My generally preferred way of working out how to build up expression trees is to start with a simple example of what you want to do written as a lambda expression, and then decompile it. That should show you how the expression tree is built - although the C# compiler gets to use the metadata associated with properties more easily than we can (we have to use Type.GetProperty).
This is always assuming I've understood you correctly... it's quite possible that I haven't.
How about this:
public static Person CreatePerson(TblPerson data)
{
// ...
}
public static Expression<Func<TblPerson, Person>> CreatePersonExpression()
{
return d => CreatePerson(d);
}
return m => (new CustomerSummary()
{
ID = m.ID,
CustomerName = m.CustomerName,
LastSalesContact = CreatePerson(m.LatestPerson)
});

Resources