I have the following database structure (just showing the pertinent tables):
I need to get a listing of all the elements in the table "Propietario" and each element must have a list of all its related elements in "Clave". Specifically, I need the field "CodigoClave" from "Clave".
Also, I need to be able to filter the results any of the fields.
This is what I've come up with so far:
int pageSizeP = (pageSize == null || pageSize == 0 || pageSize > 15) ? 15 : (int)pageSize;
int pageNumberP = (pageNumber == null || pageNumber == 0) ? 1 : (int)pageNumber;
var propietariosCount = context.Propietarios.Count();
var propietariosQuery = context.Propietarios
.AsEnumerable()
.OrderBy(p => p.Nombre).ThenBy(p => p.Apellido1).ThenBy(p => p.Apellido2)
.Select(p => new
{
Id = p.Id,
Nombre = p.Nombre,
Apellido1 = p.Apellido1,
Apellido2 = p.Apellido2,
NIF = p.NIF,
Claves = string.Join(", ", context.PropietariosFincas
.Where(pf => pf.PropietarioId == p.Id)
.Join(context.Expedientes
.Include(e => e.Clave),
pf => pf.FincaId,
e => e.FincaId,
(pf, e) => (e.Clave.CodigoClave + ((e.Clave.Alias == null) ? "" : " - " + e.Clave.Alias))
).Distinct().ToList())
// Getting an array of Claves would do;
// I could turn it into a string in the JS app
// But it's just as slow
});
if (criteriosBusqueda != "")
{
string[] aCriterios = criteriosBusqueda.Split(new string[] { "," }, StringSplitOptions.None);
CompareOptions compareOptions = CompareOptions.IgnoreCase;
if (aCriterios[0] != "")
propietariosQuery = propietariosQuery
.Where(p => p.Nombre != null)
.Where(p => p.Nombre.Replace("/", "__").ContainsIgnoreAccents(aCriterios[0], compareOptions));
if (aCriterios[1] != "")
propietariosQuery = propietariosQuery
.Where(p => p.Apellido1 != null)
.Where(p => p.Apellido1.Replace("/", "__").ContainsIgnoreAccents(aCriterios[1], compareOptions));
if (aCriterios[2] != "")
propietariosQuery = propietariosQuery
.Where(p => p.Apellido2 != null)
.Where(p => p.Apellido2.Replace("/", "__").ContainsIgnoreAccents(aCriterios[2], compareOptions));
if (aCriterios[3] != "")
propietariosQuery = propietariosQuery
.Where(p => p.NIF != null)
.Where(p => p.NIF.Replace("/", "__").ToLower().Contains(aCriterios[3].ToLower()));
if (aCriterios[4] != "")
propietariosQuery = propietariosQuery
.Where(p => p.Claves != null)
.Where(p => p.Claves.Replace("/", "__").ToLower().Contains(aCriterios[4].ToLower()));
}
var propietariosList = propietariosQuery.Skip((pageNumberP - 1) * pageSizeP).Take(pageSizeP)
.ToList();
var datosPropietarios = new
{
pageSize = pageSizeP,
pageNumber = pageNumberP,
recordsNumber = propietariosQuery.Count()
titulares = propietariosList
};
return Ok(datosPropietarios);
It works, but it's too slow (it takes several minutes). I've managed to make the initial query (the first page, unfiltered) fast by making recordsNumber = context.Propietarios.Count() but that breaks the pagination when filtering. And anyway, if I filter or if I go to a page near the end, it is again really slow.
How can I make the query faster?
My guess is that the query is pretty much traversing all the tables, so I don't know if there's even a solution that doesn't involve changing the data model.
It's because you are calling AsEnumerable, you are fetching all the data from Propietarios table to memory and the rest of operations you do after you call that method are executed using Linq to Objects instead of Linq to Entities, so your query is not translated to sql. Try removing it
Take a look of this post in case you need more info how AsEnumerable works with EF
Related
I have this query:
var query = LinqKit.PredicateBuilder.New<Resume>();
if (selectedWorkFieldID != 0)
{
query = query.And(js => js.WorkFieldID == selectedWorkFieldID);
if (!(selectedJobIDs.Contains(0) && selectedJobIDs.Count() == 1))
{
foreach (int jobID in selectedJobIDs)
query = query.Or(js => js.JobID == jobID);
}
}
var finalQuery = context.Resumes.AsNoTracking().Include(r => r.ResumeSkills)
.ThenInclude(rs => rs.Skill).Include(r => r.JobSeeker).ThenInclude(r => r.Profile)
.AsExpandable().Where(query);
count = finalQuery.Count();
resumes = finalQuery.Skip(args.Skip.Value).Take(args.Top.Value).ToList<Resume>();
This query returns All resumes not filtered ones. When I debug, the debugger curser enters the foreach block that filters with or, and there is one jobID in selectedJobIDs but the query returns all resumes. it seems the predicate builder not working at all. How to solve this?
I changed code to this:
if (selectedWorkFieldID != 0)
{
query = query.And(js => js.WorkFieldID == selectedWorkFieldID);
if (!(selectedJobIDs.Contains(0) && selectedJobIDs.Count() == 1))
{
var query2 = LinqKit.PredicateBuilder.New<Resume>();
foreach (int jobID in selectedJobIDs)
query2 = query2.Or(js => js.JobID == jobID);
query.And(query2);
}
}
and it is corrected.
I am getting a null reference exception from my bellow linq query. I have a table with an entityID(reference to another table to get translated text), but in some case i don't have proper translated text in my child table. This case i need to take lookupName field text and assign to lookupName field.
await _context.FormLookup.Where(x=>!(x.isDeleted))
.Select(x => new LookupList() {
lookupID = x.lookupID,
TransilatedName = _context.TranslatedText.FirstOrDefault(z => z.entityID == x.entityID && z.languageId == language && !(z.isDeleted)).languageText,
lookupName = x.lookupName,
itemCount = x.lookupDetails.Count(),
parent = x.parentID
}).ToListAsync();
I need to add a condition like
TransilatedName = _context.TranslatedText.FirstOrDefault(z => z.entityID == x.entityID && z.languageId == language && !(z.isDeleted)) != null ? TransilatedName = _context.TranslatedText.FirstOrDefault(z => z.entityID == x.entityID && z.languageId == language && !(z.isDeleted)).languageText : x.lookupName,
Any suggestions?
Select property LanguateText before you use FirstOrDefault:
var query = dbContext.FormLookup
.Where(x=>!(x.isDeleted))
.Select(x => new LookupList()
{
lookupID = x.lookupID,
TransilatedName = dbContext.TranslatedText
.Where(translatedText => translatedText.entityID == x.entityID
&& translatedText.languageId == language
&& !translatedText.isDeleted)
.Select(translatedText => translatedText.languageText)
.FirstOrDefault(),
...
});
I try to get a list of all innermost tables with AngleSharp. This tables doesn't contain any tables.
With HtmlAgilityPack I've realised it this way:
var wrapper = html.DocumentNode.SelectSingleNode(".//td[#class='wrapper']");
var innerMostTables = wrapper.SelectNodes(".//table [not(descendant::table)]");
With AngleSharp I've tried this, but it doesn't work:
var parser = new HtmlParser();
var document = parser.Parse(html);
var wrapper = document.All.Where(d => d.ClassName == "wrapper");
var innerMostTables = wrapper.Where(w => w.Descendents()
.Select(c => c.NodeName == "table").Count() == 0);
I could solve the problem:
foreach (IElement ch in wrapper.Descendents()
.Where(d => d.NodeName == "TABLE" && d.Descendents()
.Where(d2 => d2.NodeName == "TABLE").Count() == 0))
{
Console.WriteLine(ch.OuterHtml);
}
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 = MessageElementVModel.GetAllTreeNodes()
.Select(ame => ame.Children).Where(c =>
{
c.Where(d => getTranTypeWsName != null && d.Name == getTranTypeWsName.WsMethodName);
return false;
});
my MsgElement list:
var _msgElementList = new ObservableCollection<MessageElementViewModel>(msgElementList);
this.messageElements = _msgElementList;
NotifyPropertyChanged("MessageElements");
}
Here it is returning wrong data. It returns all the list I have a non filtered one.
Why is my out put inconsistent? I am new to LINQ.
This part of your code seems problematic:
var msgElementList = wsNameList.SingleOrDefault(x =>
{
x.Where(ame => ame.Name == getTranTypeWsName.WsMethodName);
return true;
});
You were expecting a list but you used the SingleOrDefault(), which is meant to be used in retrieving a single record.
Try this, which will retrieve msgElementList. No need to get all tree nodes first and store it in wsNameList:
// Assumed that Name is a property of Children
var msgElementList = MessageElementVModel.GetAllTreeNodes()
.Select(ame => ame.Children).Where(c => c.Name == getTranTypeWsName.WsMethodName).ToList();
Here is a solution:
var msgElementList = wsNameList.SelectMany(x => x.Where(ame => getTranTypeWsName != null && ame.Name == getTranTypeWsName.WsMethodName)).ToList();
I am having a hard time solving this problem, need code for creating a dynamic linq query in C#, asp.net. I have 5 dropdown list that searches different column in same database table and return item filtered value to a single listbox. The problem is there is no sequence that which or all or any will be selected in DDLs but the combined filtered result should show up in listbox. I have a working query that is searching and returning result in one column at a time for each DDL selection separately. Have to add where clauses with AND to add other DDL selections dynamically to this query. Thanks
public ListItemCollection searchProject(ListItemCollection projList, String searchstr, String columnName)
{
DataSet DSToReturn = new DataSet();
ListItemCollection returnItems = new ListItemCollection();
DataTable results = (from d in ((DataSet)_MyDataset).Tables["Records"].AsEnumerable()
orderby d.Field<string>("Name") ascending
where (d.Field<string>(columnName) != null)
where d[columnName].ToString().ToLower().Contains(searchstr.ToLower())
select d).CopyToDataTable();
foreach (ListItem li in projList)
{
if ((from System.Data.DataRow row in results.Rows
where li.Value.Equals(row["value"].ToString(), StringComparison.InvariantCultureIgnoreCase)
select row["value"]).Count() > 0)
returnItems.Add(li);
}
return returnItems;
}
Here's some example code for how we do it ...
private void DataPortal_Fetch(GoalCriteria criteria)
{
using (var ctx = ContextManager<Data.ExodusDataContext>
.GetManager(Database.ApplicationConnection, false))
{
this.RaiseListChangedEvents = false;
this.IsReadOnly = false;
// set option to eager load child object(s)
var opts = new System.Data.Linq.DataLoadOptions();
opts.LoadWith<Data.Goal>(row => row.Contact);
opts.LoadWith<Data.Goal>(row => row.Sales);
opts.LoadWith<Data.Goal>(row => row.Customer);
ctx.DataContext.LoadOptions = opts;
IQueryable<Data.Goal> query = ctx.DataContext.Goals;
if (criteria.Name != null) // Name
query = query.Where(row => row.Name.Contains(criteria.Name));
if (criteria.SalesId != null) // SalesId
query = query.Where(row => row.SalesId == criteria.SalesId);
if (criteria.Status != null) // Status
query = query.Where(row => row.Status == (int)criteria.Status);
if (criteria.Statuses.Count != 0) // Statuses
query = query.Where(row => criteria.Statuses.Contains((GoalStatus)row.Status));
if (criteria.ContactId != null) // ContactId
query = query.Where(row => row.ContactId == criteria.ContactId);
if (criteria.CustomerId != null) // CustomerId
query = query.Where(row => row.CustomerId == criteria.CustomerId);
if (criteria.ScheduledDate.DateFrom != DateTime.MinValue) // ScheduledDate
query = query.Where(t => t.ScheduledDate >= criteria.ScheduledDate.DateFrom);
if (criteria.ScheduledDate.DateTo != DateTime.MaxValue)
query = query.Where(t => t.ScheduledDate <= criteria.ScheduledDate.DateTo);
if (criteria.CompletedDate.DateFrom != DateTime.MinValue) // ComplatedDate
query = query.Where(t => t.CompletedDate >= criteria.CompletedDate.DateFrom);
if (criteria.CompletedDate.DateTo != DateTime.MaxValue)
query = query.Where(t => t.CompletedDate <= criteria.CompletedDate.DateTo);
if (criteria.MaximumRecords != null) // MaximumRecords
query = query.Take(criteria.MaximumRecords.Value);
var data = query.Select(row => GoalInfo.FetchGoalInfo(row));
this.AddRange(data);
this.IsReadOnly = true;
this.RaiseListChangedEvents = true;
}
}
We just check for a null value assigned to our criteria object, if it's not null then we append it to the query.