SqlFunctions.DatePart: error : function must be a literal string - c#

I am trying to use SqlFunctions.DatePart with a string which I change depending on parameters, however I can't seem to get it to work.
My code:
String dateArg = #"week";
var results = db.Orders
.GroupBy(x => new
{
Completed = SqlFunctions.DatePart(#dateArg, x.Completed)
})
.Select(x=>x.Sum(y => y.Total))
.ToList();
Fails with the following error:
The DATEPART argument to the 'SqlServer.DATEPART' function must be a literal string.

Well, #dateArg is not a literal string, it's as simple as that. "week" is, though.
If you need to vary the kind of DATEPART to group on, you'll need to split out the cases ("year", "month", "week", I'm guessing those are all that's needed). This is clumsy, but it's a result of the way compiling the expression tree down to a query operates -- just as in T-SQL itself, the first argument to DATEPART cannot be a parameter (they might as well have created separate methods DatePartYear, DatePartMonth etcetera, which would have made the restriction more obvious, and you should think of the calls like that).

I know this is an old question, but maybe this will help someone. Just use an inline if statement as follows:
string datePart = "week";
var results = db.Table.GroupBy(item =>
(datePart == "quarter") ? SqlFunctions.DatePart("quarter", item.Date) :
(datePart == "month") ? SqlFunctions.DatePart("month", item.Date) :
SqlFunctions.DatePart("week", item.Date));

var results = db.Orders
.GroupBy(x => new
{
Completed = SqlFunctions.DatePart("week", x.Completed)
})
.Select(x=>x.Sum(y => y.Total))
.ToList();

Related

LinqToDB.LinqToDBException Expressionis not an association

Hi All I am trying to do below ,I want to load an attribute value like this .
var date = db.GetTable<bbb>().Where(x => idList.Contains(x.MID))
.Select(x => x.ModifiedDate).FirstOrDefault;
var test = db.GetTable<nnn>().Where(x => xguy.Distinct().Contains(x.SID))
.LoadWith(x => x.Modified == lastPostDate);
exception:-
LinqToDB.LinqToDBException: 'Expression '(x.Modified == value(vv.x+<>c__DisplayClass25_1).lastPostDate)' is not an association.'
How can I do this?
I used the FirstOrDefault option to get one value, but I do not understand about Expression is not an association.
Your use of the "LoadWith" method is suspicious here.
LoadWith is a specialized function to load additional table data that is linked (e.g. via foreign key) to the current table row.
Based on your usage, it looks like you're just trying to set up another "Where" clause, so instead of
.LoadWith(x => x.Modified == lastPostDate);
you wanted
.Where(x => x.Modified == lastPostDate);
or alternatively, combine this with your prior Where statement to simplify things:
var test = db.GetTable<nnn>().Where(x => x.Modified == lastPostDate &&
xguy.Distinct().Contains(x.SID));
Let me know if this isn't what you intended. If this is the case, perhaps you have an SQL statement or similar that you are now trying to translate to C# LINQ, or can otherwise explain in plain English what this statement was meant to accomplish?

In Linq, is a SELECT required when WHERE is used?

If you have a Linq statement that uses a WHERE clause, for example:
var result = someCollection.Where(x => x.value > 5).Select(x => x);
Is the SELECT required, or is it redundant? It appears that I can safely omit the SELECT if I'm not trying to get at an object property, but am not sure if this is proper...
In your case No, it is not required, since you are selecting the object. So you can have:
var result = someCollection.Where(x => x.value > 5);
as far as better practice is concerned, I would remove the redundant code.
But, if you are going to select a specific property then that could be useful, like:
var result = someCollection.Where(x => x.value > 5)
.Select(x=> x.SomeSpecificProperty);
One more thing to add, with query expression you will need the select.
var result = from x in someCollection
where x.Value > 5
select x;
but at compile time the above query expression will be converted to Method Expression, without Select.
It's redundant. Select is more like the functional map (see JavaScript, Haskell, Ruby). If you aren't going to transform the input object into a different form than it is currently in, there's no need to use Select.
In Linq, is a SELECT required when WHERE is used?
No, it isnt.
No... is not necessary this time... may be if you want to select a new object different than "someCollection" it will be necessary
something like:
var result = someCollection.Where(x => x.value > 5).Select(x => new ObjName() { name = x.name, lastname = x.lastname });

Linq to sql expression tree execution zone issue

I have got a bit of an issue and was wondering if there is a way to have my cake and eat it.
Currently I have a Repository and Query style pattern for how I am using Linq2Sql, however I have got one issue and I cannot see a nice way to solve it. Here is an example of the problem:
var someDataMapper = new SomeDataMapper();
var someDataQuery = new GetSomeDataQuery();
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.Select(x => someDataMapper.Map(x));
return results.Where(x => x.SomeMappedColumn == "SomeType");
The main bits to pay attention to here are Mapper, Query, Repository and then the final where clause. I am doing this as part of a larger refactor, and we found that there were ALOT of similar queries which were getting slightly different result sets back but then mapping them the same way to a domain specific model. So take for example getting back a tbl_car and then mapping it to a Car object. So a mapper basically takes one type and spits out another, so exactly the same as what would normally happen in the select:
// Non mapped version
select(x => new Car
{
Id = x.Id,
Name = x.Name,
Owner = x.FirstName + x.Surname
});
// Mapped version
select(x => carMapper.Map(x));
So the car mapper is more re-usable on all areas which do similar queries returning same end results but doing different bits along the way. However I keep getting the error saying that Map is not able to be converted to SQL, which is fine as I dont want it to be, however I understand that as it is in an expression tree it would try to convert it.
{"Method 'SomeData Map(SomeTable)' has no supported translation to SQL."}
Finally the object that is returned and mapped is passed further up the stack for other objects to use, which make use of Linq to SQL's composition abilities to add additional criteria to the query then finally ToList() or itterate on the data returned, however they filter based on the mapped model, not the original table model, which I believe is perfectly fine as answered in a previous question:
Linq2Sql point of retrieving data
So to sum it up, can I use my mapping pattern as shown without it trying to convert that single part to SQL?
Yes, you can. Put AsEnumerable() before the last Select:
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.AsEnumerable()
.Select(x => someDataMapper.Map(x));
Please note, however, that the second Where - the one that operates on SomeMappedColumn - will now be executed in memory and not by the database. If this last where clause significantly reduces the result set this could be a problem.
An alternate approach would be to create a method that returns the expression tree of that mapping. Something like the following should work, as long as everything happening in the mapping is convertible to SQL.
Expression<Func<EntityType, Car>> GetCarMappingExpression()
{
return new Expression<Func<EntityType, Car>>(x => new Car
{
Id = x.Id,
Name = x.Name,
Owner = x.FirstName + x.Surname
});
}
Usage would be like this:
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.Select(GetCarMappingExpression());

and operator in Linq and select distinct values using linq

I am new to .net. I have a form in which there are two comboboxes cbProduct and cbBrandName and also a label lblPrice.
I am trying to implement the below code but it is showing blue scribbles to &&.
(Error: operator '&&' cannot be applied to operands of type 'lambda expression' and 'lambda expression')
I tried the below code: (not working)
lblPrice.Text = string.Empty;
lblPrice.Text = doc.Descendants("items"
).Where((x => x.Element("productname"
).Value.Equals(cbProduct.SelectedItem.ToString())) && /*blue scribbles to '&&'*/
(y => y.Element("brandname").Value.Equals(cbBrandName.SelectedItem.ToString()
))).Select(k => k.Element("price"
).Value).ToString();
My other question is that i want to make the selected values of cbProduct as distinct. The below code takes all the values instead of distinct values:
cbProduct.Items.AddRange(doc.Descendants("items"
).Select(x => x.Element("productname").Value
).ToArray<string>());//adds all products
cbProduct.SelectedIndex = 0;
giving any one answer is ok
Please assist me
Thanks in advance
It looks like you are passing 2 lambdas to the Where function and trying to logical-and (&&) them together. You can't do that. The && has to occur inside the Where lambda. Or you can chain 2 Where functions together. Something like this:
lblPrice.Text = doc.Descendants("items")
.Where(x => x.Element("productname").Value.Equals(cbProduct.SelectedItem.ToString()) &&
x.Element("brandname").Value.Equals(cbBrandName.SelectedItem.ToString()))
.Select(k => k.Element("price").Value).ToString();
The other issue I see is you are ending your query with a select, but never actually enumerating it. You probably want to do something like this:
lblPrice.Text = doc.Descendants("items")
.Where(x => x.Element("productname").Value.Equals(cbProduct.SelectedItem.ToString()) &&
x.Element("brandname").Value.Equals(cbBrandName.SelectedItem.ToString()))
.Select(k => k.Element("price").Value)
.FirstOrDefault();
Which will return the string you are looking for, or null if nothing exists (so you probably want to skip the final .ToString() call in this case, since you are already returning a string from Select and .ToString() on a null will throw an exception).
For the first question, it looks like you just want to select the one price. This code will work, assuming that the item is found by the .Single(). It will throw otherwise, in which case you should use .SingleOrDefault() and check for null on the found item.
lblPrice.Text =
doc.Descendants("items")
.Single(x => x.Element("productname").Value == cbProduct.SelectedItem.ToString() &&
x.Element("brandname").Value == cbBrandName.SelectedItem.ToString())
.Element("price").Value;
For the second question, you need to close off your .Select with a bracket, then you can call .Distinct() and .ToArray() to filter to distincts and project the result to string[]. I've also thrown an .OrderBy() in there, as there's nothing more annoying than a ComboBox in a random order. Try this:
cbProduct.Items.AddRange(doc.Descendants("items")
.Select(item => item.Element("productname").Value)
.Distinct()
.OrderBy(item => item)
.ToArray());

Issue using Where method in LINQ

Consider this line of code:
List<SIDB_TransactionInformation> transaction = SIDB.SIDB_TransactionInformations
.Where(k => k.iscurrent == true & k.objectid == SIDB.func_GetObjectID("dbo.SIDB_Module")).ToList();
List<SIDB_Module> module = SIDB.SIDB_Modules
.Where(k => k.moduleid == transaction
.Where(j => j.transactionid == k.moduleid)
.SingleOrDefault().transactionid).ToList();
I do have 2 invocation of where method in different collection. First i distinct my list via iscurrent and objectid after that I do have other invocation of where method (for SIDB_Modules) to distinct the list via moduleid where in the the values refer to the transactionid of my previous list. Now i have an error message like this Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator.
sorry i'm new in lambda expression. need help badly
I think this is what you're looking for
List<SIDB_Module> module = SIDB
.SIDB_Modules
.Where(k => transaction.Any(j => j.transactionid == k.moduleid))
.ToList();
Make a list of SIDB_Modules where there is a transaction whose transactionid is equal to the moduleid. LINQ to Sql might have an issue with Any, I don't remember, if it does you can rewrite it with an extra step like this
var transactionIds = transaction.Select(j => j.transactionid);
List<SIDB_Module> module = SIDB
.SIDB_Modules
.Where(k => transactionIds.Contains(k.moduleid))
.ToList();
If performance is an issue you might consider going with the second method and putting transactionIds into something that implements ISet<T> and has a constant time lookup.
Well, it looks like you're trying to do a join between SIDB_TransactionInformations and SIDB.SIDB_Modules. If so, try
var objectID = SIDB.func_GetObjectID("dbo.SIDB_Module");
List<SIDB_Module> modules = (from module in SIDB.SIDB_Modules
join transaction in SIDB.SIDB_TransactionInformations on module.moduleid equals transaction.transactionid
where transaction.iscurrent && transaction.objectid == objectID
select module).ToList();

Categories

Resources