This problem related to LINQ-to-entity.
I posted a similar question but it got confusing without an answer, so I am providing an example and a new shout for help.
I have a class "Colors" containing an ObservableCollection which has two members, Index and Name and populated like :
0 - Red
1 - Blue
2 - Green
and I have a database table containing a list of integers of my favorite colors. I would like to return a query with both the integer value of my favorite color and also the matching name (returned by the observablecollection) based on the index value stored in the database.
This statement in isolation works fine and returns my color name :-
string ColorName = Colors.Names.Where(x => x.Index == 1).FirstOrDefault().Name;
but when included within the LINQ-to-entity query :-
var query = from c in context.FavoriteColor
select (new Item
{
Id = c.Id,
ColorName = Colors.Names.Where(x => x.Index == c.ColorIndex).FirstOrDefault().Name
});
I get this error :
Unable to create a constant value of type 'blah blah'. Only primitive
types ('such as Int32, String, and Guid') are supported in this
context.
I understand that maybe the object is being returned within the LINQ statement but I thought by specifying the .Name notation on the end, which is a string member, it would use that and assign it to "ColorName", alas not.
Have you tried:
var query = from c in context.FavoriteColor
select new { c.Id, c.ColorIndex };
var result = from c in query.ToList()
select new Item
{
Id = c.Id,
ColorName = Colors.Names.Where(x => x.Index == c.ColorIndex).FirstOrDefault().Name
};
You are trying to use a CLR object in a database query. LINQ-to-Entities is saying you can't do that. Get the color name after the query has completed.
var dbItems = context.FavoriteColor.Select(c => new {
c.Id,
c.ColorIndex
).ToList();
var items = dbItems.Select(item => new Item {
Id = item.Id,
ColorName = Colors.Names.Where(x => x.Index == item.ColorIndex).First().Name
})
The idea here is that the call to ToList hits the database and returns the results in a CLR object. That object can then be used like any other object.
Related
This question already has answers here:
An anonymous type cannot have multiple properties with the same name
(2 answers)
Closed 2 years ago.
I need to join three entities from which I need to sum one column and the name of the column is same in two entity. In sql I can achieve this by using following query
select
a.ObjectHeadId,
a.DepartmentId,
b.Name as ObjectHeadName,
c.Name as DepartmentName,
SUM(BudgetEstimate)
from ConsolidatedAppendix1s a
inner join ObjectHeads b on b.ObjectHeadId=a.ObjectHeadId
inner join Departments c on a.DepartmentId=c.DepartmentId
group by a.ObjectHeadId, a.DepartmentId, b.Name, c.Name
While trying same in EF Core I am doing like this
consolidatedAppendixI = await _context.ConsolidatedAppendix1s
.Include(entity => entity.Department)
.Include(entity => entity.ObjectHead)
.GroupBy(r => new {
r.Department.Name,
r.DepartmentId,
r.ObjectHeadId,
r.ObjectHead.Name
})
.Select(a => new
{
ObjectHeadId = a.Key.ObjectHeadId,
DepartmentId=a.Key.DepartmentId
BudgetEstimate = a.Sum(r => r.BudgetEstimate),
ObjectHeadName= a.Key.Name,
DepartmentName = a.Key.Name,
}).ToListAsync(cancellationToken);
While doing so it shows An anonymous type cannot have multiple properties with the same name.
I can achieve this using
GroupBy(x=> 1)
but the problem here is I cannot be able to get other columns in Key while Selecting likewise it is done above for ObjectHeadId, ObjectHeadName etc.
This is because the name in the group by is same even though they are the property of different entity. How to group those column to get the sum or sql equivalent linq query?
Give the properties different names; it is essentially the same thing as the way you used AS in your SQL SELECT block:
new {
DeptName = r.Department.Name,
DeptId = r.DepartmentId, //optional rename
HeadId = r.ObjectHeadId, //optional rename
HeadName = r.ObjectHead.Name
})
And refer to these new names in the Select. You don't have to rename the DepartmentId and ObjectHeadId because they're already distinct but I find it makes code neater than to have a mix of renamed and non renamed:
new {
DeptName = r.Department.Name,
r.DepartmentId,
r.ObjectHeadId,
HeadName = r.ObjectHead.Name
})
You're of course free to choose this route if you like!
If you do not specify a property name when creating an anonymous type (by writing a name on th left hand side of an =), the compiler will infer one from the name of the property whose value you are using. Because you have two properties with the name Name (on different objects), the compiler will essentially try and create an anonymous type like this:
var x = new {
Name = thing1.Name,
Name = thing2.Name
}
Of course, this couldn't work because if you said var y = x.Name it isn't clear which Name you're talking about
As an aside,
I am trying to get a a query to work with user input. I am new to C# and lambdas so sorry for the basic question but I have hit a road block. I am getting an address input from a user in separate fields, 5 separate fields to be exact.
if (!string.IsNullOrEmpty(SessionHandler.StreetNumber))
{
allFeatures = layerFindResults.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns);
searchResults = allFeatures.Where(f => f.ColumnValues["STREETNUM"].ToLower().Contains(SessionHandler.StreetNumber.ToLower()).Select(f =>new
{
StreetNum = f.ColumnValues["STREETNUM"],
StreetName = f.ColumnValues["STR_NAME"]
}).ToList());
}
This works for getting the values in STREETNUM but i am wondering if there is a way to get other values that are associated with that column value such as Street name without the user inputting a value for them.
If this is unclear, I am sorry.
if there is a way to get other values that are associated
The Select is your friend. Select creates a projection meaning one is changing from one form of data to another. What you want to do is create a dynamic entity using the Select where you extract the related/needed data such as here where it returns the city as well:
searchResults
= allFeatures.Where( ... )
.Where( ... ) // Behaves like an `and` between the two where's.
.Select(f => new
{
Street = f.ColumnValues["STREETNUM"],
City = f.ColumnValues["City"]
})
.ToList();
I'm sure there's a way to do this with .Where() and a lambda expression, but IMO you can't beat the LINQ "SQL-like" syntax, i.e.,
searchResults = (from DataType i in allFeatures where f.StreetNum = SessionHandler.StreetNum select i).ToList(); //returns a list of matching objects
I'm writing an ASP.NET Web Pages application and in it, I have a massive LINQ to Entities query. This query pulls data from a table in the database, filters it, groups the data twice, and adds extra properties to the result set. I then loop through the table, outputting the rows.
The query is quite big, sorry:
accountOrders = db.EventOrders
.Where(order => order.EventID == eventID)
.OrderBy(order => order.ProductCode)
.GroupBy(order => new { order.AccountNum, order.Exhibitor, order.Booth })
.Select(orders =>
new {
Key = orders.Key,
ProductOrders = orders
.GroupBy(order => new { order.ProductCode, order.Product, order.Price })
.Select(productOrders =>
new {
Key = productOrders.Key,
Quantity = productOrders.Sum(item => item.Quantity),
HtmlID = String.Join(",", productOrders.Select(o => (o.OrderNum + "-" + o.OrderLine))),
AssignedLines = productOrders.SelectMany(order => order.LineAssignments)
})
})
.Select(account =>
new {
Key = account.Key,
// Property to see whether a booth number should be displayed
HasBooth = !String.IsNullOrWhiteSpace(account.Key.Booth),
HasAssignedDigitalLines = account.ProductOrders.Any(order => order.AssignedLines.Any(line => line.Type == "digital")),
// Dividing the orders into their respective product group
PhoneOrders = account.ProductOrders.Where(prod => ProductCodes.PHONE_CODES.Contains(prod.Key.ProductCode)),
InternetOrders = account.ProductOrders.Where(prod => ProductCodes.INTERNET_CODES.Contains(prod.Key.ProductCode)),
AdditionalOrders = account.ProductOrders.Where(prod => ProductCodes.ADDITIONAL_CODES.Contains(prod.Key.ProductCode))
})
.ToList();
I use the added properties to help style the output. For example, I use HasBooth property to check whether or not I should output the booth location in brackets beside the exhibitor name. The problem is I have to save this big query as an IEnumerable, meaning I get the error: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. Should I even be manipulating the query this way?
Any advice is much appreciated!
At some point, you are passing in a dynamic datatype to the method, which in turn changes the return type to simply dynamic. You can either cast the dynamic type to a type that is recognised at compile time or explicitly set the return type instead of using var.
You can read more about this issue here: http://www.mikesdotnetting.com/Article/198/Cannot-use-a-lambda-expression-as-an-argument-to-a-dynamically-dispatched-operation
I want to insert into my table a column named 'S' that will get some string value based on a value it gets from a table column.
For example: for each ID (a.z) I want to gets it's string value stored in another table. The string value is returned from another method that gets it through a Linq query.
Is it possible to call a method from Linq?
Should I do everything in the same query?
This is the structure of the information I need to get:
a.z is the ID in the first square in table #1, from this ID I get another id in table #2, and from that I can get my string value that I need to display under column 'S'.
var q = (from a in v.A join b in v.B
on a.i equals b.j
where a.k == "aaa" && a.h == 0
select new {T = a.i, S = someMethod(a.z).ToString()})
return q;
The line S = someMethod(a.z).ToString() causing the following error:
Unable to cast object of type 'System.Data.Linq.SqlClient.SqlColumn'
to type 'System.Data.Linq.SqlClient.SqlMethodCall'.
You have to execute your method call in Linq-to-Objects context, because on the database side that method call will not make sense - you can do this using AsEnumerable() - basically the rest of the query will then be evaluated as an in memory collection using Linq-to-Objects and you can use method calls as expected:
var q = (from a in v.A join b in v.B
on a.i equals b.j
where a.k == "aaa" && a.h == 0
select new {T = a.i, Z = a.z })
.AsEnumerable()
.Select(x => new { T = x.T, S = someMethod(x.Z).ToString() })
You'll want to split it up into two statements. Return the results from the query (which is what will hit the database), and then enumerate the results a second time in a separate step to transform the translation into the new object list. This second "query" won't hit the database, so you'll be able to use the someMethod() inside it.
Linq-to-Entities is a bit of a strange thing, because it makes the transition to querying the database from C# extremely seamless: but you always have to remind yourself, "This C# is going to get translated into some SQL." And as a result, you have to ask yourself, "Can all this C# actually get executed as SQL?" If it can't - if you're calling someMethod() inside it - your query is going to have problems. And the usual solution is to split it up.
(The other answer from #BrokenGlass, using .AsEnumerable(), is basically another way to do just that.)
That is an old question, but I see nobody mention one "hack", that allows to call methods during select without reiterating. Idea is to use constructor and in constructor you can call whatever you wish (at least it works fine in LINQ with NHibernate, not sure about LINQ2SQL or EF, but I guess it should be the same).
Below I have source code for benchmark program, it looks like reiterating approach in my case is about twice slower than constructor approach and I guess there's no wonder - my business logic was minimal, so things like iteration and memory allocation matters.
Also I wished there was better way to say, that this or that should not be tried to execute on database,
// Here are the results of selecting sum of 1 million ints on my machine:
// Name Iterations Percent
// reiterate 294 53.3575317604356%
// constructor 551 100%
public class A
{
public A()
{
}
public A(int b, int c)
{
Result = Sum(b, c);
}
public int Result { get; set; }
public static int Sum(int source1, int source2)
{
return source1 + source2;
}
}
class Program
{
static void Main(string[] args)
{
var range = Enumerable.Range(1, 1000000).ToList();
BenchmarkIt.Benchmark.This("reiterate", () =>
{
var tst = range
.Select(x => new { b = x, c = x })
.AsEnumerable()
.Select(x => new A
{
Result = A.Sum(x.b, x.c)
})
.ToList();
})
.Against.This("constructor", () =>
{
var tst = range
.Select(x => new A(x, x))
.ToList();
})
.For(60)
.Seconds()
.PrintComparison();
Console.ReadKey();
}
}
I have a simple table:
ID | Value
When I do this:
var sequence = from c in valuesVault.GetTable()
select new {RandomIDX = Guid.NewGuid(), c.ID, c.Value};
each element in the projection has the value of the same guid... How do I write this so that I get a different random guid value for each of my element in the projection?
Edit
To clarify on the issue. The GetTable() method simply calls this:
return this.context.GetTable<T>();
where the this.contenxt is the DataContext of type T.
The itteration is done as it's always done, nothing fancy:
foreach (var c in seq)
{
Trace.WriteLine(c.RandomIDX + " " + c.Value);
}
Output:
bf59c94e-119c-4eaf-a0d5-3bb91699b04d What is/was your mother's maiden name?
bf59c94e-119c-4eaf-a0d5-3bb91699b04d What was the last name of one of your high school English teachers?
bf59c94e-119c-4eaf-a0d5-3bb91699b04d In elementary school, what was your best friend's first and last name?
Edit 2
Using out the box linq2Sql Provider. I had built some generic wrappers around it but they do not alter the way IQuaryable or IEnumerable function in the code.
What is underneath valuesVault.GetTable()?
You probably have a Linq provider such as Linq 2 SQL.
That means that valuesVault.GetTable() is of type IQueryable which in turn means that the entire query becomes an expression.
An expression is a query that is defined but not yet executed.
When sequence is being iterated over, the query is executed using the Linq provider and that Linq provider and one of the steps it has to perform is to execute this expression: Guid.NewGuid(). Most Linq providers cannot pass that expression to the underlying source (SQL Server wouldn't know what to do with it) so it gets executed once and the result of the execution returned with the rest of the result.
What you could do is to force the valuesVault.GetTable() expression to become a collection by calling the .ToList() or .ToArray() methods. This executes the expression and returns an IEnumerable which represents an in-memory collection.
When performing queries against an IEnumerable, the execution is not passed to the Linq provider but executed by the .NET runtime.
In your case this means that the expression Guid.NewGuid() can be executed correctly.
Try this:
var sequence = from c in valuesVault.GetTable().ToArray()
select new {RandomIDX = Guid.NewGuid(), c.ID, c.Value};
Notice the .ToArray() there. That is what will make the statement go from IQueryable to IEnumerable and that will change its behaviour.
I think it's happening when it gets translated into SQL (ie: it's the database doing it). Since you have no WHERE clauses in your example, you could just do:
var sequence = from c in valuesVault.GetTable().ToList()
select new { RandomID = Guid.NewGuid(), c.ID, c.Value };
Which forces Guid.NewGuid() to be executed in the client. However, it's ugly if your table grows and you start adding filtering clauses. You could solve it by using a second LINQ query that projects a second result set with your new GUIDs:
var sequence = from c in valuesVault.GetTable()
where c.Value > 10
select new { c.ID, c.Value };
var finalSequence = from s in sequence.ToList()
select new { RandomID = Guid.NewGuid(), s.ID, s.Value };
Seems to work for me.
List<int> a = new List<int> {10, 11, 12, 13};
var v = a.Select(i => new {ID = Guid.NewGuid(), I = i});
foreach (var item in v)
{
Console.WriteLine(item);
}
output
{ ID = b760f0c8-8dcc-458e-a924-4401ce02e04c, I = 10 }
{ ID = 2d4a0b17-54d3-4d69-8a5c-d2387e50f054, I = 11 }
{ ID = 906e1dc7-6de4-4f8d-b1cd-c129142a277a, I = 12 }
{ ID = 6a67ef6b-a7fe-4650-a8d7-4d2d3b77e761, I = 13 }
I'm not able to reproduce this behavior with a simple LINQ query. Sample:
List<int> y = new List<int> { 0, 1, 2, 3, 4, 5 };
var result = y.Select(x => new { Guid = Guid.NewGuid(), Id = x }).ToList();
I'm imagining if you try to convert your Table value to a List in Linq, then perform your select, you'll get different Guids.