I have the following query.
var query = Repository.Query<Product>()
.Where(p => !p.IsDeleted && p.Article.ArticleSections.Count() > 0)
.Select(p => new
{
OfficeId = p.TariffCategory.Office.Id,
Office = p.TariffCategory.Office.Name,
Category = p.TariffCategory.Description,
ArticleId = p.Article.Id,
Article = p.Article.Title,
Destinations = p.ProductDestinations.OrderBy(pd => pd.Destination.Description).Select(pd => new { Id = pd.DestinationId, Name = pd.Destination.Description }),
GlobalDestinations = p.AllDestinationsInOffice,
p.Article.LastReviewedDate,
p.Article.CreatedDate,
p.Article.CreatedByEmployee
});
query = query.Concat(Repository.Query<Package>()
.Where(pkg => !pkg.IsDeleted && pkg.Article.ArticleSections.Count() > 0)
.Select(pkg => new
{
OfficeId = pkg.TariffCategory.Office.Id,
Office = pkg.TariffCategory.Office.Name,
Category = pkg.TariffCategory.Description,
ArticleId = pkg.Article.Id,
Article = pkg.Article.Title,
Destinations = pkg.PackageDestinations.OrderBy(pd => pd.Destination.Description).Select(pd => new { Id = pd.DestinationId, Name = pd.Destination.Description }),
GlobalDestinations = pkg.AllDestinationsInOffice,
pkg.Article.LastReviewedDate,
pkg.Article.CreatedDate,
pkg.Article.CreatedByEmployee
}));
query = query.Concat(Repository.Query<Backgrounder>()
.Where(bkgd => !bkgd.IsDeleted && bkgd.Article.ArticleSections.Count() > 0)
.Select(bkgd => new
{
OfficeId = bkgd.TariffCategory.Office.Id,
Office = bkgd.TariffCategory.Office.Name,
Category = bkgd.TariffCategory.Description,
ArticleId = bkgd.Article.Id,
Article = bkgd.Article.Title,
Destinations = bkgd.BackgrounderDestinations.OrderBy(bd => bd.Destination.Description).Select(bd => new { Id = bd.DestinationId, Name = bd.Destination.Description }),
GlobalDestinations = bkgd.AllDestinationsInOffice,
bkgd.Article.LastReviewedDate,
bkgd.Article.CreatedDate,
bkgd.Article.CreatedByEmployee
}));
// Apply filters
if (OfficeIds.Any())
query = query.Where(a => OfficeIds.Contains(a.OfficeId));
if (DestinationIds.Any())
query = query.Where(a => a.GlobalDestinations || a.Destinations.Any(d => DestinationIds.Contains(d.Id)));
if (!string.IsNullOrEmpty(ArticleTitle))
query = query.Where(a => a.Article.Contains(ArticleTitle));
if (!string.IsNullOrEmpty(TariffCategory))
query = query.Where(a => a.Category.Contains(TariffCategory));
// Sort results
query = query.OrderBy(a=> a.Office).ThenBy(a => a.Category).ThenBy(a => a.Article);
var articles = query.ToList();
However, when I run this query I get an exception.
The nested query is not supported. Operation1='UnionAll' Operation2='MultiStreamNest'
The query searches through articles in my database. Because articles can be related to a Product, Package or Backgrounder, and I need information from the related table, I concatenate separate queries for each of those items.
I've narrowed it down to the assignment to Destinatons. Apparently, this constitute a query within the query associated with Concat(). (If I remove the second two queries and the associated Concat() calls, it works fine.)
After looking at this a while, I'm having trouble seeing another way to construct my query without making it much, much slower.
Does anyone see any tricks I might have missed to work around the exception?
Unfortunately there are no tricks. The only reasonable way I see to make this work without totally rewriting it is to execute the queries separately (applying all possible filters) and then do Concat and ordering in memory like this:
var queries = new []
{
Repository.Query<Product>()
.Where(p => !p.IsDeleted && p.Article.ArticleSections.Count() > 0)
.Select(p => new
{
OfficeId = p.TariffCategory.Office.Id,
Office = p.TariffCategory.Office.Name,
Category = p.TariffCategory.Description,
ArticleId = p.Article.Id,
Article = p.Article.Title,
Destinations = p.ProductDestinations.OrderBy(pd => pd.Destination.Description).Select(pd => new { Id = pd.DestinationId, Name = pd.Destination.Description }),
GlobalDestinations = p.AllDestinationsInOffice,
p.Article.LastReviewedDate,
p.Article.CreatedDate,
p.Article.CreatedByEmployee
}),
Repository.Query<Package>()
.Where(pkg => !pkg.IsDeleted && pkg.Article.ArticleSections.Count() > 0)
.Select(pkg => new
{
OfficeId = pkg.TariffCategory.Office.Id,
Office = pkg.TariffCategory.Office.Name,
Category = pkg.TariffCategory.Description,
ArticleId = pkg.Article.Id,
Article = pkg.Article.Title,
Destinations = pkg.PackageDestinations.OrderBy(pd => pd.Destination.Description).Select(pd => new { Id = pd.DestinationId, Name = pd.Destination.Description }),
GlobalDestinations = pkg.AllDestinationsInOffice,
pkg.Article.LastReviewedDate,
pkg.Article.CreatedDate,
pkg.Article.CreatedByEmployee
}),
Repository.Query<Backgrounder>()
.Where(bkgd => !bkgd.IsDeleted && bkgd.Article.ArticleSections.Count() > 0)
.Select(bkgd => new
{
OfficeId = bkgd.TariffCategory.Office.Id,
Office = bkgd.TariffCategory.Office.Name,
Category = bkgd.TariffCategory.Description,
ArticleId = bkgd.Article.Id,
Article = bkgd.Article.Title,
Destinations = bkgd.BackgrounderDestinations.OrderBy(bd => bd.Destination.Description).Select(bd => new { Id = bd.DestinationId, Name = bd.Destination.Description }),
GlobalDestinations = bkgd.AllDestinationsInOffice,
bkgd.Article.LastReviewedDate,
bkgd.Article.CreatedDate,
bkgd.Article.CreatedByEmployee
}),
};
// Apply filters
if (OfficeIds.Any())
for (int i = 0; i < queries.Length; i++) queries[i] = queries[i].Where(a => OfficeIds.Contains(a.OfficeId));
if (DestinationIds.Any())
for (int i = 0; i < queries.Length; i++) queries[i] = queries[i].Where(a => a.GlobalDestinations || a.Destinations.Any(d => DestinationIds.Contains(d.Id)));
if (!string.IsNullOrEmpty(ArticleTitle))
for (int i = 0; i < queries.Length; i++) queries[i] = queries[i].Where(a => a.Article.Contains(ArticleTitle));
if (!string.IsNullOrEmpty(TariffCategory))
for (int i = 0; i < queries.Length; i++) queries[i] = queries[i].Where(a => a.Category.Contains(TariffCategory));
// Switch to LINQ to Objects and concatenate the results
var result = queries.Select(query => query.AsEnumerable()).Aggregate(Enumerable.Concat);
// Sort results
result = result.OrderBy(a=> a.Office).ThenBy(a => a.Category).ThenBy(a => a.Article);
var articles = result.ToList();
Related
Im having 5 users and 5 services.
I must catch if more than one user(s) have same service. So I created a dictionary:
//JMBGS represents users ids
List<string> multipleJMBGs = new List<string>();
multipleJMBGs.Add(data.jMBG);
multipleJMBGs.Add(data.secondPersonJMBG);
multipleJMBGs.Add(data.thirdPersonJMBG);
multipleJMBGs.Add(data.fourthPersonJMBG);
multipleJMBGs.Add(data.fifthPersonJMBG);
multipleJMBGs.RemoveAll(x => string.IsNullOrEmpty(x));
//object Service has Id property, and I need to check if more than one user has the same service
var serviceForClient = data?.Schedules[0]?.Service;
var serviceForFirstFamilyMember = data?.Schedules[1]?.Service;
var serviceForSecondFamilyMember = data?.Schedules[2]?.Service;
var serviceForThirdFamilyMember = data?.Schedules[3]?.Service;
var serviceForFourthFamilyMember = data?.Schedules[4]?.Service;
Dictionary<string, EmployeeTableDay.ServiceDTO> userService = new Dictionary<string, EmployeeTableDay.ServiceDTO>();
userService.Add(data.jMBG, serviceForClient);
userService.Add(data.secondPersonJMBG, serviceForFirstFamilyMember);
userService.Add(data.thirdPersonJMBG, serviceForSecondFamilyMember);
userService.Add(data.fourthPersonJMBG, serviceForThirdFamilyMember);
userService.Add(data.fifthPersonJMBG, serviceForFourthFamilyMember);
What I want to have as flag (true/false):
different users can have different services
different users can have same services
same users, can not have same service
same users can have multiple services
UPDATE #1:
List<string> multipleJMBGs = new List<string>();
multipleJMBGs.Add(data.jMBG);
multipleJMBGs.Add(data.secondPersonJMBG);
multipleJMBGs.Add(data.thirdPersonJMBG);
multipleJMBGs.Add(data.fourthPersonJMBG);
multipleJMBGs.Add(data.fifthPersonJMBG);
multipleJMBGs.RemoveAll(x => string.IsNullOrEmpty(x));
var countedSchedules = data?.Schedules?.Count();
var serviceIdForClient = 0;
var serviceIdForFirstFamilyMember = 0;
var serviceIdForSecondFamilyMember = 0;
var serviceIdForThirdFamilyMember = 0;
var serviceIdForFourthFamilyMember = 0;
List<int> servicesIds = new List<int>();
if(countedSchedules >= 1 && data?.Schedules[0]?.Service != null)
{
serviceIdForClient = data.Schedules[0].Service.Id;
servicesIds.Add(serviceIdForClient);
}
if (countedSchedules >= 2 && data?.Schedules[1]?.Service != null)
{
serviceIdForFirstFamilyMember = data.Schedules[1].Service.Id;
servicesIds.Add(serviceIdForFirstFamilyMember);
}
if (countedSchedules >= 3 && data?.Schedules[2]?.Service != null)
{
serviceIdForSecondFamilyMember = data.Schedules[2].Service.Id;
servicesIds.Add(serviceIdForSecondFamilyMember);
}
if (countedSchedules >= 4 && data?.Schedules[3]?.Service != null)
{
serviceIdForThirdFamilyMember = data.Schedules[3].Service.Id;
servicesIds.Add(serviceIdForThirdFamilyMember);
}
if (countedSchedules == 5 && data?.Schedules[4]?.Service != null)
{
serviceIdForFourthFamilyMember = data.Schedules[4].Service.Id;
servicesIds.Add(serviceIdForFourthFamilyMember);
}
servicesIds = servicesIds.Where(x => x > 0).ToList();
//because dictionary throws an exception
for (int i = 0; i < countedSchedules; i++)
{
multipleJMBGs[i] = i + " _ " + multipleJMBGs[i];
}
//create dictionary from two lists
var dic = multipleJMBGs.Zip(servicesIds, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);
var duplicateServices = dic.GroupBy(x => x.Value).Where(x => x.Count() > 1)
.Select(x => new { ServiceId = x.Key, Users = x.ToList() });
var duplicateUsers = dic.GroupBy(x => x.Key.Substring(3,x.Key.Length-3)).Where(x => x.Count() > 1)
.Select(x => new { User = x.Key, Services = x.ToList() });
if(duplicateServices > 1 && duplicateUsers.Count > 1)
{
//show a message that it ca't be proceeed further
}
else
{
//continue
}
You can group the services by Id to get information on duplicates:
var groups = data?.Schedules
.Select((service, index) => (service, index))
.GroupBy(x => x.service.Id);
foreach (var g in groups) {
if (g.Count() == 1) {
Console.WriteLine(
$"Service Id {g.Key} exists once for user index {g.First().index}");
} else {
string indexes = String.Join(", ", g.Select(t => t.index.ToString()));
Console.WriteLine(
$"Service Id {g.Key} is shared by user indexes {indexes}");
}
}
If you don't call multipleJMBGs.RemoveAll(...), then the indexes in the users list will match the indexes of the services. So you can easily get the JMBG assigned to a service.
var groups = data?.Schedules
.Select((service, index) => (service, index))
.GroupBy(x => x.service.Id);
foreach (var g in groups) {
if (g.Count() == 1) { // Service is unique
var service = g.First().service;
int index = g.First().index;
string user = multipleJMBGs[index];
...
} else { // Services assigned to more than one user.
var serviceId = g.Key;
var service = g.First().service;
foreach (var t in g) {
int index = t.index;
string user = multipleJMBGs[index];
...
}
...
}
}
Purely answering the question on how to check for duplicates within your dictionary:
You could group the values of your dictionary and look for duplicates that way.
var containsDuplicates = userService.GroupBy(x => x.Value).Any(x => x.Count() > 1);
If you want to actually see which services are used multiple times by which users, create the following grouping:
var duplicateServices = userService.GroupBy(x => x.Value).Where(x => x.Count() > 1)
.Select(x => new { Service = x.Key, Users = x.ToList() });
UPDATE #1:
You don't necessarily have to group up both of these lists if you just need to check if any of the two contain duplicates.
We could simply compare the total count of the lists with the count of the list when we remove all possible duplicates:
var duplicateServices = countedSchedules != data?.Schedules?.Distinct().Count();
var duplicateUsers = multipleJMBGs.Count() != multipleJMBGs.Distinct().Count();
UPDATE #2:
Sounds like you want to join the two lists together and not necessarily convert it to a dictionary, what we want to do instead is create a new List so we can group that on the combination of the two properties.
var containsDuplicates = multipleJMBGs.Zip(serviceIds, (JMBG, serviceId) => new { JMBG, serviceId })
.Where(x => !string.IsNullOrEmpty(x.JMBG) && x.serviceId > 0) // Filter AFTER zipping the two lists together
.GroupBy(x => x).Any(x => x.Count() > 1);
Do be aware that you are removing elements in both lists, meaning that the order might not be correct. You could instead add a Where clause after you zip the lists like in the example above.
I have the following code..
var GetStock = db.tabStocks.Where(x => x.SourceDocRef == InvoiceNumber.Text);
List<tabStock> tbs = new List<tabStock>();
foreach (var Stk in GetStock)
{
switch (GetStock.Any(y => y.ProductSKU == Stk.ProductSKU && y.Id != Stk.Id))
{
case true:
if (!(tbs.AsEnumerable().Any(x => x.Id == Stk.Id))) {
tbs.Add(Stk);
}//tbs.AddRange(GetStock2.Where(g => g.ProductSKU == Stk.ProductSKU && g.Id != Stk.Id));
var GetOthers = GetStock.Where(x => x.Id != Stk.Id && x.ProductSKU == Stk.ProductSKU );
foreach (var Gt in GetOthers) {
if (!(tbs.AsEnumerable().Any(x => x.Id == Gt.Id))) {
tbs.Add(Gt);
}
} break;
}
}
//Group and Remove tbs
Literal1.Text += tbs.AsEnumerable().Count();
try
{
var GroupIt = tbs.GroupBy(x => x.ProductSKU ).AsEnumerable()
.Select(g => new tabStock
{
ProductName = g.FirstOrDefault().ProductName,
ProductSKU = g.FirstOrDefault().ProductSKU,
Qty = g.Sum(n => n.Qty).Value,
OutQty = g.Sum(n => n.Qty).Value,
Bal = (db.tabStocks.Any(x => x.ProductSKU == g.FirstOrDefault().ProductSKU && x.SourceDocRef != g.FirstOrDefault().SourceDocRef && x.Id < g.OrderBy(t => t.Id).FirstOrDefault().Id) ? db.tabStocks.Where(x => x.ProductSKU == g.FirstOrDefault().ProductSKU && x.SourceDocRef != g.FirstOrDefault().SourceDocRef && x.Id < g.OrderBy(t => t.Id).FirstOrDefault().Id).OrderByDescending(x => x.Id).FirstOrDefault().Bal - g.Sum(f => f.Qty).Value : (0 - g.Sum(f => f.Qty)).Value).Value,
TransactionRef = g.FirstOrDefault().TransactionRef,
CreatedBy = g.FirstOrDefault().CreatedBy,
CreationDate = g.FirstOrDefault().CreationDate,
SourceDocRef = g.FirstOrDefault().SourceDocRef,
InQty = 0,
transactionType = "Sale",
UnitCost = g.FirstOrDefault().UnitCost.Value,
Received = 0,
TotalValuation = 0,
});
foreach (var NewStk in GroupIt.AsEnumerable())
{
tabStock stk = new tabStock();
stk.ProductName = NewStk.ProductName;
stk.ProductSKU = NewStk.ProductSKU;
stk.Qty = NewStk.Qty;
stk.OutQty = NewStk.OutQty;
stk.Bal = NewStk.Bal;
stk.transactionType = NewStk.transactionType;
stk.TransactionRef = NewStk.TransactionRef;
stk.CreatedBy = NewStk.CreatedBy;
stk.CreationDate = NewStk.CreationDate;
stk.SourceDocRef = NewStk.SourceDocRef;
stk.InQty = NewStk.InQty;
stk.UnitCost = NewStk.UnitCost;
stk.Received = 0;
stk.TotalValuation = 0;
db.tabStocks.Add(stk);
}
foreach (var OldStk in tbs.AsEnumerable())
{
db.tabStocks.Remove(OldStk);
}
db.SaveChanges();
For some reason i have this error:
Unable to create a constant value of type
'Type'. Only primitive types or enumeration types are supported in this context
Can anyone help me point to what this could be. I have looked at a lot of others related, nothing seems to work.. toList(), AsEnumerable(). Where is my code wrong please.
Hello every one i have string containing Address and list of Areas from Db, i want to get the area from address string which is present in both list of areas and address string.how can i do this without looping because through looping it will take to much time. Any solution please through regular expression or any other approach.
var data = _context.OrderDetails.Where(c => c.ConsignmentId == cId)
.Select(c => new {address = c.DeliveryAddress, cityId = c.CityId}).ToList();
string EncryptedConsId = _customEncryptionDecryption.Encode(cId);
Regex re = new Regex(#"^(.*?(\bkarachi\b)[^$]*)$");
MatchCollection cityA = re.Matches(data[0].address.ToLower());
if (cityA.Count != 0)
{
var cityNameA = cityA[0].Groups[2];
if (cityNameA.Value == "karachi")
{
var areasForCityA = _context.Areas.Where(a => a.CityId == 1).ToList();
}
}
i have solve my problm by doing this,Thanks to all of You Thank you so much
var areas = _context.Areas.Where(a => a.CityId == data[0].cityId).ToList();
for (int i = 0; i < areas.Count; i++)
{
var result = data[0].address.ToLower().Contains(areas[i].Title.ToLower());
if (result)
{
AreaId = areas[i].Id;
CityId = data[0].cityId;
var order = _context.OrderDetails.Where(o => o.ConsignmentId == cId).SingleOrDefault();
order.AreaId = AreaId;
_context.SaveChanges();
break;
}
}
In my web api i need to execute a method from linq query itself. My linq query code snippet belongs to method is shown below which calls local method to get required data.
var onlineData = (from od in db.RTLS_ONLINEPERSONSTATUS
let zoneIds = db.RTLS_PERSONSTATUS_HISTORY.Where(p => p.person_id == od.PERSONID).OrderByDescending(z => z.stime > startOfThisDay && z.stime < DateTime.Now).Select(z => z.zone_id).ToList()
let zoneIdsArray = this.getZoneList((zoneIds.ToArray()))
let fzones = zoneIdsArray.Select(z => z).Take(5)
select new OnlineDataInfoDTO
{
P_ID = od.PERSONID,
T_ID = (int)od.TAGID,
LOCS = fzones.ToList()
}
public int[] getZoneList(decimal[] zoneIdsArray)
{
int[] zoneIds = Array.ConvertAll(zoneIdsArray, x => (int)x);
List<int> list = zoneIds.ToList();
for (int c = 1; c < zoneIdsArray.Count(); c++)
{
if (zoneIdsArray[c] == zoneIdsArray[c - 1])
{
list.Remove((int)zoneIdsArray[c]);
}
}
return list.ToArray();
}
I am getting exception at let zoneIdsArray = this.getZoneList((zoneIds.ToArray())), is there any way to solve this problem. I got logic to solve my problem from this link(Linq query to get person visited zones of current day ), the given logic is absolutely fine for my requirement but i am facing problem while executing it.
One way to achieve that would be to perform the projection on the client instead of the underlying LINQ provider. This can be done by separating your query into 2 steps:
var peopleStatus =
from od in db.RTLS_ONLINEPERSONSTATUS
let zoneIds = db.RTLS_PERSONSTATUS_HISTORY
.Where(p => p.person_id == od.PERSONID)
.OrderByDescending(z => z.stime > startOfThisDay && z.stime < DateTime.Now)
.Select(z => z.zone_id)
.ToList()
select new
{
Person = od,
ZoneIds = zoneIds,
};
var onlineData =
from od in peopleStatus.ToList()
let zoneIdsArray = this.getZoneList((od.ZoneIds.ToArray()))
let fzones = zoneIdsArray.Select(z => z).Take(5)
select new OnlineDataInfoDTO
{
P_ID = od.Person.PERSONID,
T_ID = (int)od.Person.TAGID,
LOCS = fzones.ToList()
};
I have this LINQ
var questions = _context.Questions
.Where(q => q.Level.Level == level)
.Select(q => new QuestionViewModel
{
Text = q.Text,
Id = q.Id,
IsMultiSelected = q.IsMultiSelected,
AnswerViewModels = q.Answers
.Select(
a => new AnswerViewModel
{
Checked = false,
Text = a.Text,
Id = a.Id
}) as List<AnswerViewModel>
});
return questions.ToList();
I get
Exception Details: System.NotSupportedException: The 'TypeAs' expression with an input of type 'System.Collections.Generic.IEnumerable`1' and a check of type 'System.Collections.Generic.List`1' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.
in
return questions.ToList();
I don't use anonymous types in select. How to resolve this error ?
UPDATE
I coded some solution
List<QuestionViewModel> result = new List<QuestionViewModel>();
var questions = from q in _context.Questions
where q.Level.Level == level
select new QuestionViewModel()
{
Text = q.Text,
Id = q.Id,
IsMultiSelected = q.IsMultiSelected,
AnswerViewModels = from a in q.Answers
select new AnswerViewModel
{
Text = a.Text,
Id = a.Id,
Checked = false
}
};
var qList = questions.ToList();
for(int i = 0; i < questions.Count(); i++)
{
var q = qList[i]; //question
var a = q.AnswerViewModels.ToList(); //answers for question
var answers = new List<AnswerViewModel>(); //List answers
for(int j = 0; j < a.Count(); j++)
{
//add new Answer from IEnumerable<AnswerViewQuestion> to List<...>
answers.Add(new AnswerViewModel
{
Checked = false,
Id = a[j].Id,
Text = a[j].Text
});
}
result.Add(q);
}
How to optimize ?
The problem is with
.Select(a => new AnswerViewModel { ... }) as List<AnswerViewModel>
It should be
.Select(a => new AnswerViewModel { ... }).ToList()
The reason is that the correct way to convert a LINQ-generated IEnumerable to a List is of course by calling the ToList extension method, which you are already doing in the last line given.
Try something like this:
var questions = _context.Questions
.Where(q => q.Level.Level == level)
.Select(q => new QuestionViewModel
{
Text = q.Text,
Id = q.Id,
IsMultiSelected = q.IsMultiSelected,
AnswerViewModels = q.Answers
.Select(
a => new AnswerViewModel
{
Checked = false,
Text = a.Text,
Id = a.Id
})
}).AsEnumerable().Select(x => new QuestionViewModel
{
Text = x.Text,
Id = x.Id,
IsMultiSelected = x.IsMultiSelected,
AnswerViewModels = x.Answers.ToList()
});
return questions.ToList();