method to map entity to a poco getting invoke error - c#

I am getting the "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." error with this bit of code.
Function Call
IEnumerable<OrderListItem> orders;
orders = _service.GetAllForUser<OrderListItem>(userName, mapOrderToListItem);
var foo = orders.ToArray();
Functions
public IEnumerable<T> GetAllForUser<T>(string userName, Func<Order, T> mapper)
{
string displayName = _adService.GetDisplayName(userName);
return _repo.Query().Where(x => x.OrderedBy == userName)
.OrderBy(x => x.OrderDate)
.Select(x => mapper(x))
.AsEnumerable();
}
private OrderListItem mapOrderToListItem(Order order)
{
OrderListItem result = new OrderListItem
{
DeliveryLoc = order.OrderGroup.DeliveryLocation.Name,
Department = order.OrderGroup.Department.Name,
Id = order.Id,
OrderDate = order.OrderDate,
OrderedBy = order.OrderedBy,
Status = !order.ApprovedDate.HasValue ? "SUBMITTED" : !order.ReceivedDate.HasValue ? order.ApprovalStatus == ApprovalStatus.Approved ? "APPROVED" : "DENIED" : !order.FilledDate.HasValue ? "RECEIVED" : "FILLED"
};
return result;
}
however i do not receive the invoke error with this bit of code
Function Call
IEnumerable<ProductListItem> products;
products = _service.SearchAll<ProductListItem>(sSearch, 0, all, orderBy, sortDir, productListItemMapper);
var foo = products.ToArray();
Function
public IEnumerable<T> SearchAll<T>(string sSearch, int skip, int take, Func<Product, IComparable> sortCol, DAL.SortDir sortDir, Func<Product, T> mapper)
{
switch (sortDir)
{
case DAL.SortDir.asc:
return _repo.Query().Where(r => (r.Name.Contains(sSearch) || r.CatalogNumber.Contains(sSearch)))
.OrderBy(sortCol).Skip(skip).Take(take).Select(x => mapper(x)).AsEnumerable();
case DAL.SortDir.dsc:
return _repo.Query().Where(r => (r.Name.Contains(sSearch) || r.CatalogNumber.Contains(sSearch)))
.OrderByDescending(sortCol).Skip(skip).Take(take).Select(x => mapper(x)).AsEnumerable();
default:
throw new ArgumentException("sortDir");
}
}
private ProductListItem productListItemMapper(Product product)
{
ProductListItem output = new ProductListItem
{
Id = product.Id,
Location = product.WarehouseLocation.Name,
Name = product.Name,
Active = product.Active,
Number = product.CatalogNumber,
Units = product.UnitOfMeasure.Name,
UnitsId = product.UnitOfMeasureId,
LocationId = product.WarehouseLocationId
};
return output;
}
i feel like i'm just blind and missing something simple. Why does it work for products but not for orders?

Just for the error message I can think it's because you're trying to use the invoke on the sql server side, try to convert the result first to a collection (list/array) then use your function, so instead "select(e => mapper(e))" do first a ToList() then a select. This is because and IQueryable executes your commands on sql and sql doesn't know about your mapper function.
Edit: keep in mind ToList will retrieve all the records from the db.

Related

Is there a way to declare a C# lambda and immediately call it?

It's possible to declare a lambda function and immediately call it:
Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);
I'm wondering if it's possible to do so in one line, e.g. something like
int output = (input) => { return 1; }(0);
which gives a compiler error "Method name expected". Casting to Func<int, int> doesn't work either:
int output = (Func<int, int>)((input) => { return 1; })(0);
gives the same error, and for reasons mentioned below I'd like to avoid having to explicitly specify the input argument type (the first int).
You're probably wondering why I want to do this, instead of just embedding the code directly, e.g. int output = 1;. The reason is as follows: I've generated a reference for a SOAP webservice with svcutil, which because of the nested elements generates extremely long class names, which I'd like to avoid having to type out. So instead of
var o = await client.GetOrderAsync(request);
return new Order {
OrderDate = o.OrderDate,
...
Shipments = o.Shipment_Order == null ? new Shipment[0]
o.Shipment_Order.Select(sh => new Shipment {
ShipmentID = sh.ShipmentID,
...
Address = CreateAddress(sh.ReceiverAddress_Shipment);
}).ToArray()
};
and a separate CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address) method (real names are even longer, and I have very limited control about the form), I'd like to write
var o = await client.GetOrderAsync(request);
return new Order {
OrderDate = o.OrderDate,
...
Shipments = o.Shipment_Order == null ? new Shipment[0]
o.Shipment_Order.Select(sh => new Shipment {
ShipmentID = sh.ShipmentID,
...
Address = sh.ReceiverAddress_Shipment == null ? null : () => {
var a = sh.ReceiverAddress_Shipment.Address;
return new Address {
Street = a.Street
...
};
}()
}).ToArray()
};
I know I could write
Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
Street = sh.ReceiverAddress_Shipment.Address.Street,
...
}
but even that (the sh.ReceiverAddress_Shipment.Address part) becomes very repetitive if there are many fields. Declaring a lambda and immediately calling it would be more elegant less characters to write.
Instead of trying to cast the lambda, I propose you use a small helper function:
public static TOut Exec<TIn, TOut>(Func<TIn, TOut> func, TIn input) => func(input);
which you could then use like this: int x = Exec(myVar => myVar + 2, 0);. This reads a lot nicer to me than the alternatives suggested here.
It's ugly, but it's possible:
int output = ((Func<int, int>)(input => { return 1; }))(0);
Anonymous functions, including lambda expressions, are implicitly convertible to a delegate that matches their signature, but this syntax requires the lambda to be enclosed in parentheses.
The above can be simplified as well:
int output = ((Func<int, int>)(input => 1))(0);
Lambda literals in C# have a curious distinction in that their meaning is dependent on their type. They are essentially overloaded on their return type which is something does not exist anywhere else in C#. (Numeric literals are somewhat similar.)
The exact same lambda literal can either evaluate to an anonymous function that you can execute (i.e. a Func/Action) or an abstract representation of the operations inside of the Body, kind of like an Abstract Syntax Tree (i.e. a LINQ Expression Tree).
The latter is, for example, how LINQ to SQL, LINQ to XML, etc. work: the lambdas do not evaluate to executable code, they evaluate to LINQ Expression Trees, and the LINQ provider can then use those Expression Trees to understand what the body of the lambda is doing and generate e.g. a SQL Query from that.
In your case, there is no way for the compiler to know wheter the lambda literal is supposed to be evaluated to a Func or a LINQ Expression. That is why Johnathan Barclay's answer works: it gives a type to the lambda expression and therefore, the compiler knows that you want a Func with compiled code that executes the body of your lambda instead of an un-evaluated LINQ Expression Tree that represents the code inside the body of the lambda.
You could inline the declaration of the Func by doing
int output = (new Func<int, int>(() => { return 1; }))(0);
and immediately invoking it.
You can also create the alias in the Select method
var o = await client.GetOrderAsync(request);
return new Order {
OrderDate = o.OrderDate,
...
Shipments = o.Shipment_Order == null ? new Shipment[0]
o.Shipment_Order.Select(sh => {
var s = sh.ReceiverAddress_Shipment;
var a = s.Address;
return new Shipment {
ShipmentID = sh.ShipmentID,
...
Address = s == null ?
null :
new Address {
Street = a.Street
...
}
};
}).ToArray()
};
or with the ?? operator
var o = await client.GetOrderAsync(request);
return new Order {
OrderDate = o.OrderDate,
...
Shipments = o.Shipment_Order?.Select(sh => {
var s = sh.ReceiverAddress_Shipment;
var a = s.Address;
return new Shipment {
ShipmentID = sh.ShipmentID,
...
Address = s == null ?
null :
new Address {
Street = a.Street
...
}
};
}).ToArray() ?? new Shipment[0]
};
If you don't mind violating a few of the extension methods design guidelines, extension methods combined with null-conditional operator ?. can take you reasonably far:
public static class Extensions
{
public static TOut Map<TIn, TOut>(this TIn value, Func<TIn, TOut> map)
where TIn : class
=> value == null ? default(TOut) : map(value);
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> items)
=> items ?? Enumerable.Empty<T>();
}
will give you this:
return new Order
{
OrderDate = o.OrderDate,
Shipments = o.Shipment_Order.OrEmpty().Select(sh => new Shipment
{
ShipmentID = sh.ShipmentID,
Address = sh.ReceiverAddress_Shipment?.Address.Map(a => new Address
{
Street = a.Street
})
}).ToArray()
};
and if you mostly need arrays, then override ToArray extension method to encapsulate a few more method calls:
public static TOut[] ToArray<TIn, TOut>(this IEnumerable<TIn> items, Func<TIn, TOut> map)
=> items == null ? new TOut[0] : items.Select(map).ToArray();
resulting in:
return new Order
{
OrderDate = o.OrderDate,
Shipments = o.Shipment_Order.ToArray(sh => new Shipment
{
ShipmentID = sh.ShipmentID,
Address = sh.ReceiverAddress_Shipment?.Address.Map(a => new Address
{
Street = a.Street
})
})
};

MongoDB projection toListAsync() method not supported

I am trying to use projection in my query and get the following error:
"The result operation MongoDB.Driver.Linq.Expressions.ResultOperators.ListResultOperator is not supported."
Here is the code:
public async Task<IEnumerable<Listing>> LoadAllUserListings(string userId)
{
var result = _context.Listing.Aggregate().Match(l => l.OwnerId == userId || l.Sales.Any(a => a.Owner.Id == userId)).
Project(l => new Listing
{
Id = l.Id,
Reference = l.Reference,
OwnerId = l.OwnerId,
Sales = l.Sales.Where(a => a.Owner.Id == userId || a.Manager.Id == userId).ToList(),
Products = l.Products,
Status = l.Status,
DueDate = l.DueDate
}).ToListAsync();
return await result;
}
It does not appear to like the ToListAsync call. I got this code snippet from the following answer:
https://stackoverflow.com/questions/50904811/mongodb-c-sharp-filter-and-get-all-subdocuments
There reason I am using projection is to omit some fields which the user should not see (depending on the role). Any help on this would be appreciated.
Thanks in advance.
The problem occurs in that line:
Sales = l.Sales.Where(a => a.Owner.Id == userId || a.Manager.Id == userId).ToList()
What happens here ? MongoDB driver takes this expression and tries to translate it to aggregation framework syntax. There's a $filter operator which can be run on nested collection and driver is able to translate .Where() to that operator however there's nothing corresponding for .ToList() at the end of that expression and that's why it fails.
So the fix is fairly easy: you just need to use IEnumerable<T> instead of List<T> for Sales property and then get rid of that .ToList() so your code will look like this:
public async Task<IEnumerable<Listing>> LoadAllUserListings(string userId)
{
var result = _context.Listing.Aggregate().Match(l => l.OwnerId == userId || l.Sales.Any(a => a.Owner.Id == userId)).
Project(l => new Listing
{
Id = l.Id,
Reference = l.Reference,
OwnerId = l.OwnerId,
Sales = l.Sales.Where(a => a.Owner.Id == userId || a.Manager.Id == userId),
Products = l.Products,
Status = l.Status,
DueDate = l.DueDate
}).ToListAsync();
return await result;
}

LINQ IN type query to get records based on result set of another query

UserAuthorizations table has Company per User wise, and I want to get the list of Companies for the Users which are assigned as to them.
// GET: odata/Companies/GetUserCompanies
[EnableQuery]
public IQueryable<UserAuthorization> GetUserCompanies()
{
List<int> userCompanyIds = db.UserAuthorizations.Where(u => u.Cwid == this.UserId).Select(s => s.CompanyId).ToList();
return db.Companies.Where(m => m.Id.ToString().Contains(userCompanyIds));
}
For above I am getting error like
Cannot convert from 'System.Collections.Generic.List<int>' to 'string'
try it
public IQueryable<Company> GetUserCompanies()
{
List<int> userCompanyIds = db.UserAuthorizations.Where(u => u.Cwid == this.UserId).Select(s => s.CompanyId).ToList();
return db.Companies.Where(m => userCompanyIds.Contains(m.Id));
}

return the only record value in a table

ClientAccountAccess table will only ever have one record, containing an ID and a GUID.
I want to return the GUID as string.
private static string GetAccessCode()
{
using (EPOSEntities db = new EPOSEntities())
{
string clientAccessCode = from e in db.ClientAccountAccesses
where string.IsNullOrWhiteSpace(e.GUID)
select e.GUID;
return clientAccessCode;
}
}
select is throwing an error saying cant convert Ienumerable to string, but I dont want to create an IEnumerable clientAccessCode, as I said there will only ever be one record in this table and I want to return the value of the GUID.
?
thanks for replies
Use FirstOrDefault() or SingleOrDefault() if there should not be more than one matched result:
private static string GetAccessCode()
{
using (EPOSEntities db = new EPOSEntities())
{
var clientAccessCodes = from e in db.ClientAccountAccesses
where string.IsNullOrWhiteSpace(e.GUID)
select e.GUID;
return clientAccessCodes.FirstOrDefault();
}
}
Note - result of query will be of type IEnumerable<string>. You also can use lambda syntax:
private static string GetAccessCode()
{
using (EPOSEntities db = new EPOSEntities())
{
return db.ClientAccountAccesses
.Where(e => String.IsNullOrWhiteSpace(e.GUID))
.Select(e => e.GUID)
.FirstOrDefault();
}
}

How to refactor multiple similar Linq-To-Sql queries?

Suppose I have the two following Linq-To-SQL queries I want to refactor:
var someValue1 = 0;
var someValue2= 0;
var query1 = db.TableAs.Where( a => a.TableBs.Count() > someValue1 )
.Take( 10 );
var query2 = db.TableAs.Where( a => a.TableBs.First().item1 == someValue2)
.Take( 10 );
Note that only the Where parameter changes. There is any way to put the query inside a method and pass the Where parameter as an argument?
All the solutions posted in the previous question have been tried and failed in runtime when I try to enumerate the result.
The exception thrown was: "Unsupported overload used for query operator 'Where'"
Absolutely. You'd write:
public IQueryable<A> First10(Expression<Func<A,bool>> predicate)
{
return db.TableAs.Where(predicate).Take(10);
}
(That's assuming that TableA is IQueryable<A>.)
Call it with:
var someValue1 = 0;
var someValue2= 0;
var query1 = First10(a => a.TableBs.Count() > someValue1);
var query2 = First10(a => a.TableBs.First().item1 == someValue2);
I believe that will work...
The difference between this and the answers to your previous question is basically that this method takes Expression<Func<T,bool>> instead of just Func<T,bool> so it ends up using Queryable.Where instead of Enumerable.Where.
If you really want reusability you can try to write your own operators. E.g. instead of repeatedly writing:
var query =
Products
.Where(p => p.Description.Contains(description))
.Where(p => p.Discontinued == discontinued);
you can write simple methods:
public static IEnumerable<Product> ByName(this IEnumerable<Product> products, string description)
{
return products.Where(p => p.Description.Contains(description));
}
public static IEnumerable<Product> AreDiscontinued(IEnumerable<Product> products, bool isDiscontinued)
{
return products.Where(p => p.Discontinued == discontinued);
}
and then use it like this:
var query = Products.ByName("widget").AreDiscontinued(false);

Categories