I'm trying to figure out how to put multiple values into a WHERE clause; this is the kind of thing you'd use a IN clause for in SQL.
My current code:
if (Log.Count() == 1)
{
items = itemTable
.Where(Item => Item.id == Log[0].i_id)
.ToCollectionView();
}
else if (Log.Count() == 2)
{
items = itemTable
.Where(Item => Item.id == Log[0].i_id || Item.id == Log[1].i_id)
.ToCollectionView();
}
else if (Log.Count() == 3)
{
items = itemTable
.Where(Item => Item.id == Log[0].i_id || Item.id == Log[1].i_id || Item.id == Log[2].i_id)
.ToCollectionView();
}
It's pretty nasty. I can't find a way to put multiple values into that WHERE clause without a big if statement. Any ideas?
Try this instead:
items = itemTable
.Where(Item => Log.Any(logItem => logItem.i_id == Item.id))
.ToCollectionView();
Edit: (in response to the "not supported exception")
You can try this alternative to see if the backend supports it:
var ids = Log.Select(logItem => logItem.i_id).ToList();
var items = itemTable
.Where(Item => ids.Contains(Item.id))
.ToCollectionView();
items = itemTable.Where(Item => Log.Any(i => i.i_id == Item.id)).ToCollectionView();
I faced the same issue. Using Any or Contains as others have suggested gave me a Not Supported Exception. I posted on the Azure Mobile Services forum and was told that IN is not supported yet. They advised I use an extension method which worked perfectly for me. Below is the code I used.
public static class Extensions
{
public async static Task<List<T>> In<T>(this IMobileServiceTable<T> table, List<int> ids)
{
var query = new StringBuilder("$filter=(");
for (int i = 0; i < ids.Count; i++)
{
query.AppendFormat("id eq {0}", ids[i]); //don't forget to url escape and 'quote' strings
if (i < ids.Count - 1)
{
query.Append(" or ");
}
}
query.Append(")");
var list = await table.ReadAsync(query.ToString());
var items = list.Select(i => MobileServiceTableSerializer.Deserialize<T>(i)).ToList();
return items;
}
}
Your list can be populated by calling the extension method like this:
FavoriteJokesList = await jokeItemTable.In(favoriteJokeIds);
Source: http://social.msdn.microsoft.com/Forums/en-US/azuremobile/thread/b573ff6c-1f6b-4846-b44d-4678e3d26f66
Just for the record, in the newest Version of the Azure Mobile Service SDK (1.0), this works:
var ids = Log.Select(logItem => logItem.i_id).ToList();
var items = await itemTable
.Where(Item => ids.Contains(Item.id))
.ToCollectionAsync();
Related
I have a bug that I need more than one result from a foreach without creating a new collection in the method. I need to get rid of the foreach however I don`t know what LINQ method to use.
I have tried,
return basket.Items.SelectMany(
item => item.Id == orderComplimentaryUtilities.Where(o => o.Id));
public static IEnumerable<OrderItem> WhichUtilitiesAreAlreadyInBasket(
this
IEnumerable<OrderComplimentaryUtility.OrderComplimentaryUtility>
orderComplimentaryUtilities,
Order basket)
{
if (basket == null || orderComplimentaryUtilities == null)
{
return Enumerable.Empty<OrderItem>();
}
foreach (var orderComplimentaryUtility in orderComplimentaryUtilities)
{
return basket.Items.Where(item => item.Id == orderComplimentaryUtility.Id);
}
return Enumerable.Empty<OrderItem>();
}
It appears that you are looking to join the data from two sequences (orderComplimentaryUtilities and basket), and return the data from basket where they match by id.
You can accomplish this with a LINQ join:
public static IEnumerable<OrderItem> WhichUtilitiesAreAlreadyInBasket(
this IEnumerable<OrderComplimentaryUtility.OrderComplimentaryUtility> orderComplimentaryUtilities,
Order basket)
{
if (basket == null || orderComplimentaryUtilities == null)
{
return Enumerable.Empty<OrderItem>();
}
var items = orderComplimentaryUtilities
.Join(basket,
u => u.ID,
b => b.ID,
(u, b) => b);
return items;
}
You can use Contains if you separate out the ids into a collection:
var ids = orderComplimentaryUtility.Select(i => i.id).ToArray();
return basket.Items.Where(item => ids.Contains(item.Id));
If this is all in-memory, you could inline the Select into the Where clause, but that may not work if you're querying a SQL data source that cannot convert the Select into an IN clause.
I'm trying to select a subset of two lists of the same object as part of a where clause, and getting an error.
{"Expression of type 'System.Linq.IQueryable1[<>f__AnonymousType772[System.Int32,System.Int32]]' cannot be used for parameter of type 'System.Linq.IQueryable1[Entity.Entities.QuestionModuleQuestionDto]' of method 'System.Linq.IQueryable1[Entity.Entities.QuestionModuleQuestionDto] Where[QuestionModuleQuestionDto](System.Linq.IQueryable1[Entity.Entities.QuestionModuleQuestionDto], System.Linq.Expressions.Expression1[System.Func`2[Entity.Entities.QuestionModuleQuestionDto,System.Boolean]])' (Parameter 'arg0')"}
public async Task<bool> ValidateQuestions(List<QuestionModuleQuestion> questions)
{
var questionModules = await _context.QuestionModule
.Include(qm => qm.Questions)
Where(qm =>
qm.Questions.Select(q => new {q.QuestionId, q.Sequence})
.Intersect(questions.Select(q => new {q.QuestionId, q.Sequence})).Any())
.ToListAsync();
return questionModules.Any(qm => qm.Questions.Count == questions.Count);
}
I rewrote the clause to look like the following, but I'm not too terribly fond of this approach.
var questionModules = await _context.QuestionModule.Include(qm => qm.Questions)
.Where(qm => qm.Questions.Any(qmq => questions.Any(question =>
question.QuestionId == qmq.QuestionId && question.Sequence == qmq.Sequence)))
.ToListAsync();
EF Core has limited support for operations with local collections. You can use only Contains and very simple Any.
You can use this extension FilterByItems and rewrite query in the following way. Query refactored to be effective and I hope that I have not changed requirements.
public async Task<bool> ValidateQuestions(List<QuestionModuleQuestion> questions)
{
var questionCount = questions.Count;
var query = _context.QuestionModule
Where(qm =>
qm.Questions.AsQueryable()
.FilterByItems(questions, (q, i) => q.QuestionId == i.QuestionId && q.Sequence == i.Sequence, true)
.Count() == questionCount);
return await questionModules.AnyAsync();
}
function for get list of documents name only with distinct...
public static List<DocumentTypeModel> GetUploadedDocumentsName(int TicketId)
{
List<DocumentTypeModel> documents = new List<DocumentTypeModel>();
using (var db = new UnitOfWork())
{
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).Distinct().ToList();
}
return documents;
}
currently result is this -
Affidavit in Case of Cancelled Will/No Will
Affidavit in Case of Cancelled Will/No Will
Allotment Letter
Allotment Letter
Death Certificate
Death Certificate
Lease Deed
Lease Deed
Photo Identity of Applicant
Photo Identity of Applicant
Possession Letter
Possession Letter
Registered/Unregistered Will
Registered/Unregistered Will
You can use groupby and select first option like this:
List<DocumentTypeModel> documents = new List<DocumentTypeModel>();
using (var db = new UnitOfWork())
{
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).ToList();
documents = documents.GroupBy(x => x.DocumentTypeNameEnglish).Select(g => g.First());
}
Distinct() doesn't work like you tried on objects. Use IComparer to get this working https://support.microsoft.com/en-us/kb/320727
Create a comparer class
public class DocumentTypeModelComparer: IComparer
{
int IComparer.Compare(object a, object b)
{
if(a.Id == b.ID)
return 0;
else
return 1;
}
}
Now in your lambda expression
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).ToList().Distinct(new DocumentTypeModelComparer()).ToList();
You are selecting the documenttypemodel and this is the distinct part (so all fields are checked), you probably want the distinct by via https://github.com/morelinq/MoreLINQ, or you can use group by with first see(linq distinct or group by multiple properties).
The other option is to select only the DocumentTypeNameEnglish field and you will get the unique documents.
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new { documentTypes =s.tbl_MstDocumentType.DocumentTypeNameEnglish}).Distinct().ToList();
Hopefully this is what you want, if not can you post more details?
https://social.msdn.microsoft.com/Forums/en-US/6303da53-c412-4ce6-a983-bd6bd87f516b/how-to-do-a-select-distinct-with-ef?forum=adodotnetentityframework
Kindly refer this link Its useful to you
Switch to the below per Vladimir's comment:
.ToList().Distinct();
I'm new with LINQ. I'm using this function:
public IEnumerable<Vendedores> GetVendedores()
{
using (var context = new OhmioEntities())
{
Vendedores _allvendors= new Vendedores();
_allvendors.Nombre = "All Vendors";
_allvendors.ID_Vendedor = -1;
var query = context.Vendedores;
var _vendors= query.Where(f => f.Activo == true).OrderBy(o=>Nombre).ToList();
_vendors.Insert(0, _allvendors);
return _vendors;
}
}
It should give me order list of active vendors. The where part work fine, but the order is ignored and the records after the .ToList are in the original table order. What i'm i doing wrong?
Thank you!
I think you need o.Nombre instead of Nombre
var _vendors = query
.Where(f => f.Activo)
.OrderBy(o=> o.Nombre)
.ToList();
Also f => f.Activo == true can be written as f => f.Activo.
it should be this way:
var _vendors= query.Where(f => f.Activo == true).OrderBy(o=>o.Nombre).ToList();
I want to take the first 10 records, but it is ignoring the .take(10) and returning all of the rows.
[WebMethod]
public string getTopTenFeatured(int tab)
{
using (MyDataContext db = new MyDataContext())
{
IQueryable q = tab == 0? q = db.Items.Where(x => x.isFeatured == true)
.OrderBy(x => x.title).Select(x=> x.title).Take(10):
q = db.Authors.Where(x=> x.isFeatured == true)
.OrderBy(x => x.text).Select(x => x.text).Take(10);
StringBuilder sb = new StringBuilder();
sb.Append("<ul>");
int i = 0;
foreach (var n in q)
{
i++;
sb.AppendFormat("<li>{0}. {1}</li>", i, n);
}
sb.Append("</ul>");
return sb.ToString();
}
}
Edit: Nothing wrong here, Projects as opposed to web sites appparently have to be rebuilded manually. Hitting refresh in the browser does not do this automatically like a web site type project.
I think you have too many q='s in there. Try this
IQueryable q = (tab == 0) ?
db.Items
.Where(x => x.isFeatured == true)
.OrderBy(x => x.title)
.Select(x=> x.title).Take(10)
: db.Authors.Where(x=> x.isFeatured == true)
.OrderBy(x => x.text)
.Select(x => x.text).Take(10);
Also, if you don't mind some constructive criticism, I don't think your web method should conflate these two return results. Perhaps have a separate web method for each -- more strongly typed. The checking of the tab should be done on the client side and the appropriate web method should be called. Just a thought. :-)