System.InvalidOperationException: 'Sequence contains no matching element' - asp.net-core-mvc

May I know why that error keeps pointing to "String isEmailVerified ...."?
public JsonResult GetMemberCounts([FromBody] ChartFilterRequest filter)
{
DateTime startDate = DateTime.Parse(filter.MainFilter.First(m => m.Name == "startDate").Value as string);
DateTime endDate = DateTime.Parse(filter.MainFilter.First(m => m.Name == "endDate").Value as string);
String isEmailVerified = filter.MainFilter.First(m => m.Name == "isEmailVerified").Value as string;
var data = _dashboardComponent.GetMemberCount(startDate, endDate, isEmailVerified);
return new JsonResult(data);
}

Try using FirstOrDefault and LastOrDefault instead of First and Last, these methods will return the default value of the type they are invoked for if no elements match the lambda expression you provide as a parameter.
In your project, You just use filter.MainFilter.First(xxxx) to select the data, So if no elements match the lambda expression you provide as a parameter,First() will throw an exception, So here will report this error.

Related

Retrieve single element from LINQ query

Working with LINQ for the first time in a while and trying to clean something up. I have the following statements:
var element = await _Entities.References
.Where(db => db.LoadId == request.LoadId && db.ReferenceCode == "123")
.OrderByDescending(rec => rec.Created).FirstOrDefaultAsync(cancellationToken);
if (element != null) {
dto.ElementValue = element.Value;
}
I'd like to condense this into a single statement if possible but I was having trouble getting just the value from the await method.
You could do something like this:
dto.ElementValue = (await _Entity.References
.Where(db => db.LoadId == request.LoadId && db.ReferenceCode == "123")
.OrderByDescending(rec => rec.Created)
.FirstOrDefaultAsync(cancellationToken))?.Value
?? dto.ElementValue;
Note that technically this changes the behaviour of the code. Previously, if the query doesn't return a result, the ElementValue property is not touched. With a one-liner, if the query doesn't return a result, the ElementValue getter and setter will both be called.
Also, if the query returns a result whose Value is null, the ElementValue property will be set to itself rather than null.

How to search exact record by asp.net web api with help of lamda expresion

I am facing a problem in searching a exact record by LINQ query method in ASP.NET Web API my controller. This is my code:
[HttpGet]
[Route("api/tblProducts/AllProductbySearch/{SearchText}")]
[ResponseType(typeof(IEnumerable<tblProduct>))]
public IHttpActionResult AllProductbySearch(string SearchText)
{
IEnumerable<tblProduct> tblProduct = db.tblProducts.Where(x=>x.PrdKeyword.Contains(SearchText)).AsEnumerable();
if (tblProduct == null)
{
return NotFound();
}
return Ok(tblProduct);
}
In this I am searching the record with value have keyword column and getting the result but problem is that it is not giving exact result for example if in database two record have keyword column value like shirt and another have Tshirt
Then if I pass shirt in SearchText or pass tshirt in SearchText it is giving both record while I want one record which exact match with SearchText. Please help me
My updated action method code is:
[HttpGet]
[Route("api/tblProducts/AllProductbySearch/{SearchText}")]
[ResponseType(typeof(IEnumerable<tblProduct>))]
public IHttpActionResult AllProductbySearch(string SearchText)
{
IEnumerable<tblProduct> tblProduct = db.tblProducts.Where(x => CheckWord(x.PrdKeyword, SearchText)).AsEnumerable();
if (tblProduct == null)
{
return NotFound();
}
return Ok(tblProduct);
}
private bool CheckWord(string source, string searchWord)
{
var punctuation = source.Where(Char.IsPunctuation).Distinct().ToArray();
var words = source.Split().Select(x => x.Trim(punctuation));
return words.Contains(searchWord, StringComparer.OrdinalIgnoreCase);
}
But is throwing the same error - http 500
EDITED 2
Added ToList() - db.tblProducts.ToList().... In this case we retrieve all data from Data Base and filter them in memory. If we don't retrieve all data before filtering .Net tries to create request to SQL with filtration and can't because there are .Net methods as CheckWord().
I think we can get required data without retrieving all table into memory, but don't know how. As variant we should write specific Stored Procedure and use it. Get all into memory is a simplest way (but not faster)
Please, look at this post Get only Whole Words from a .Contains() statement
Actually, for your case solution can be:
IEnumerable<tblProduct> tblProduct = db.tblProducts.ToList()
.Where(x => Regex.Match(x.PrdKeyword, $#"\b{SearchText}\b", RegexOptions.IgnoreCase).Success)
.AsEnumerable();
Option 2. Without regexp:
public static bool CheckWord(string source, string searchWord)
{
if (source == null)
return false;
var punctuation = source.Where(Char.IsPunctuation).Distinct().ToArray();
var words = source.Split().Select(x => x.Trim(punctuation));
return words.Contains(searchWord, StringComparer.OrdinalIgnoreCase);
}
[HttpGet]
[Route("api/tblProducts/AllProductbySearch/{SearchText}")]
[ResponseType(typeof(IEnumerable<tblProduct>))]
public IHttpActionResult AllProductbySearch(string SearchText)
{
IEnumerable<tblProduct> tblProduct = db.tblProducts.ToList()
.Where(x => CheckWord(x.PrdKeyword, SearchText)).AsEnumerable();
if (tblProduct == null)
{
return NotFound();
}
return Ok(tblProduct);
}
Sorry, I'm from phone now, there can be mistakes here. Will try it in 3-4 hour
You are making a simple mistake. You just need to use .Equals instead of .Contains.
When you use Contains .Net will check if the input string is part of the main string. Whereas Equals will check for exact match.
var mainStr = “long string with Hello World”;
var inputStr = “Hello”;
var status = mainStr.Contains(inputStr);
// Value of status is `true`
status = mainStr.Equals(inputStr);
// Value of status is `false`
So your code should look like this:
IEnumerable<tblProduct> tblProduct = db.tblProducts.Where(x=>x.PrdKeyword.Equals(SearchText)).AsEnumerable();
.Equals can also help you find exact match with or without having case-sensitive check in force. The single-parameterised method does a Case-Sensitive check whereas the other overridden methods of .Equals gives you an opportunity to ignore it.
Hope this helps!

Unable to cast object of type WhereSelectListIterator 2 System.Collections.Generic.List

I am working on these lists to get an item that matches the selected item from the combobox.
private void InitializaMessageElement()
{
if (_selectedTransactionWsName != null)
{
get a transaction webservice name matching the selected item from the drop down here the output=TestWS which is correct
var getTranTypeWsName = TransactionTypeVModel
.GetAllTransactionTypes()
.FirstOrDefault(transTypes =>
transTypes.WsMethodName == _selectedTransactionWsName);
Loop the list of wsnames from the treenode list. Here it gives me all the node I have which is correct.
var wsNameList = MessageElementVModel
.GetAllTreeNodes().Select(ame =>
ame.Children).ToList();//. == getTranTypeWsName.WsMethodName);
find the getTranTypeWsName.WsMethodName in the wsNameList. Here is where I have the problem:
var msgElementList = wsNameList.Select(x => x.Where(ame => getTranTypeWsName != null && ame.Name == getTranTypeWsName.WsMethodName)).ToList();
my MsgElement list:
MsgElementObsList = new ObservableCollection<MessageElementViewModel>(msgElementList);
this.messageElements = _msgElementList;
NotifyPropertyChanged("MessageElements");
}
Here it is throwing the cast error. why is it not working? I am new to LINQ. thanks
As the error is trying to tell you, LINQ methods return special iterator types the implement IEnumerable<T>; they do not return List<T>.
This enables deferred execution.
Since the object isn't actually a List<T>, you can't cast it to a type that it isn't.
If you need a List<T>, you can either call ToList(), or skip LINQ entirely and use List<T>.ConvertAll(), which is like Select(), but does return List<T>.
Modify
MsgElementObsList = new ObservableCollection<MessageElementViewModel>((List<MessageElementViewModel>) msgElementList);
to
MsgElementObsList = new ObservableCollection<MessageElementViewModel>(msgElementList);
This is because although all lists are enumerable, all enumerables are not lists, and this one happens not to be one.
Also, your bool error has to do with returning true in the select. Here's the fixed code for that:
var msgElementList = wsNameList.Select(x =>
x.Where(ame => ame.Name == getTranTypeWsName.WsMethodName));

Linq pass null to Where clause

I have method which accept expression for Linq Where clause. Sometimes I would like to ignore Where clause and do not use it.
I have tried to pass null to the method like this
GetUsersView(null)
but got exception. How correctly do this?
private IQueryable<UserView> GetUsersView(Expression<Func<User, bool>> expression)
{
return _userRepository.GetAll().
Where(expression).
Select(p => new UserView
{
Id = p.Id,
Active = p.Orders.Any(c => c.Active && (c.TransactionType == TransactionType.Order || c.TransactionType == TransactionType.Subscription)),
DateStamp = p.DateStamp,
Email = p.Email,
FirstName = p.FirstName,
LastName = p.LastName,
Message = p.Message,
UsersManager = p.Orders.Select(o => o.Product).Any(w => w.UsersManager && w.Active)
});
}
Passing nulls to methods is a horrible idea. Passing u => true is not very readable either. Create two methods instead - one which has parameter, and other, which don't have. Also I see your method have two responsibilities - it filters users, and converts them to UserViews. I think filtering users by predicate should occur in repository.
You can also create extension method IQueryable<UserView> ToViews(this IQueryable<User> source).
public static IQueryable<UserView> ToViews(this IQueryable<User> source)
{
return source.Select(u => new UserView
{
Id = u.Id,
Active = u.Orders.Any(o => o.Active &&
(o.TransactionType == TransactionType.Order ||
o.TransactionType == TransactionType.Subscription)),
DateStamp = u.DateStamp,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName,
Message = u.Message,
UsersManager = u.Orders.Select(o => o.Product)
.Any(p => p.UsersManager && p.Active)
});
}
In this case code will look like:
private IQueryable<UserView> GetUserViews()
{
return _userRepository.GetAll().ToViews();
}
private IQueryable<UserView> GetUserViews(Expression<Func<User, bool>> predicate)
{
// move filtering to repository
return _userRepository.GetAll(predicate).ToViews();
}
Try using
GetUsersView(u=>true);
or if you would prefer not to type the expression all the time, you can create an overloaded function that provides a default expression.
IQueryable<UserView> GetUsersView()
{
return GetUsersView(u=>true);
}

Only primitive types ('such as Int32, String, and Guid') are supported in this context when I try updating my viewmodel

I am having some trouble with a linq query I am trying to write.
I am trying to use the repository pattern without to much luck. Basically I have a list of transactions and a 2nd list which contains the description field that maps against a field in my case StoreItemID
public static IList<TransactionViewModel> All()
{
var result = (IList<TransactionViewModel>)HttpContext.Current.Session["Transactions"];
if (result == null)
{
var rewardTypes = BusinessItemRepository.GetItemTypes(StoreID);
HttpContext.Current.Session["Transactions"] =
result =
(from item in new MyEntities().TransactionEntries
select new TransactionViewModel()
{
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
}).ToList();
}
return result;
}
public static List<BusinessItemViewModel>GetItemTypes(int storeID)
{
var result = (List<BusinessItemViewModel>)HttpContext.Current.Session["ItemTypes"];
if (result == null)
{
HttpContext.Current.Session["ItemTypes"] = result =
(from items in new MyEntities().StoreItems
where items.IsDeleted == false && items.StoreID == storeID
select new BusinessItemViewModel()
{
ItemDescription = items.Description,
StoreID = items.StoreID,
StoreItemID = items.StoreItemID
}).ToList();
}
return result;
However I get this error
Unable to create a constant value of type 'MyMVC.ViewModels.BusinessItemViewModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
I know its this line of code as if I comment it out it works ok
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
How can I map ItemDescription against my list of itemTypes?
Any help would be great :)
This line has a problem:
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription,
Since you are using FirstOrDefault you will get null as default value for a reference type if there is no item that satifies the condition, then you'd get an exception when trying to access ItemDescription - either use First() if there always will be at least one match or check and define a default property value for ItemDescription to use if there is none:
ItemDescription = itemTypes.Any(r=>r.StoreItemID==item.StoreItemID)
? itemTypes.First(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription
: "My Default",
If itemTypes is IEnumerable then it can't be used in your query (which is what the error message is telling you), because the query provider doesn't know what to do with it. So assuming the that itemTypes is based on a table in the same db as TransactionEntities, then you can use a join to achieve the same goal:
using (var entities = new MyEntities())
{
HttpContext.Current.Session["Transactions"] = result =
(from item in new entities.TransactionEntries
join itemType in entities.ItemTypes on item.StoreItemID equals itemType.StoreItemID
select new TransactionViewModel()
{
ItemDescription = itemType.ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
CustomerName = rewards.CardID//TODO: Get customer name
}).ToList();
}
I don't know the structure of your database, but hopefully you get the idea.
I had this error due a nullable integer in my LINQ query.
Adding a check within my query it solved my problem.
query with problem:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.Equals(y.OBJ_ID));
query with problem solved:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.HasValue && s.Obj_Id.Value.Equals(y.OBJ_ID));

Resources