I have to find in dictionary in a mongo database.
class Person
{
public string Name { get; set; }
public Dictionary<int,string> AgePersons { get; set; }
}
I have tried two options:
_database.Find(v => v.Name == "test" && v.AgePersons.Any(el => el.Key == 12 && el.Value == "person_name")).ToList();
I got the error: The expression tree is not supported: {document}{dc}'
_database.Find(v => v.Name == "test" && v.AgePersons[12] == "person_name"]).ToList();
I got the error: 'v.AgePersons.get_Item(12) is not supported.'
How can I solve?
A simple option would be to store your objects as:
public class Document
{
public String Name { get; set; }
public List<Item> People { get; set; }
}
public class Item
{
public String Key { get; set; }
public String Value { get; set; }
}
Then map your data on read/write between your classes and these.
A perhaps better option would be to reshape your data when storing into:
public class Item
{
public String Name { get; set; }
public String Key { get; set; }
public String Value { get; set; }
}
Then searching for a Name by Key and Value will be a lot easier and you can still collect the Items into a single object by querying by name or by aggregating and using groupBy name as the last step in the pipeline.
This would also enabling simpler adding or removing of single items without altering large documents.
Related
I hope this isn't a foolishly simple question. Im very simply trying to figure out how to manipulate a relatively simple table in SQLite through C#.
Im looking to take a parameter and search a List of Arrays for one such array where the parameter matches, and return a related variable within that same array.
For example where an array in the list might be.
Name IATA
Brisbane BNE
The sqlbind:
public static List<Airport> LoadAirports()
{
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
var output = cnn.Query<Airport>("select * from Airport", new DynamicParameters());
return output.ToList();
}
}
The Class:
class Airport
{
int Id { get; set; }
string Name { get; set; }
string LocationName { get; set; }
string IATA { get; set; }
string PortType { get; set; }
string PortOwner { get; set; }
string MotherPort { get; set; }
bool Active { get; set; }
bool IsApplyMeetAndGreet { get; set; }
decimal MeetAndGreet { get; set; }
}
The main Program:
List<Airport> Airports = new List<Airport>();
public FreightCalculator()
{
LoadAirportsList();
string OriginName = OriginInput.Value;
var OriginAirport = Airports.Where(s => s.Name == OriginName);
}
private void LoadAirportsList()
{
Airports = SqliteDataAccess.LoadAirports();
}
Ive tried various combinations of Where, Equals, For each indexing etc. Always getting an error of some kind.
The Error with the above Airports.Where is that the s.Name is inaccessible due to its protection level.
If I do:
var OriginAirport = Airports.Where(Name => Name == OriginName);
I get an error where the operand == cannot be used with Airport and String (Though Name is a string in Airport.)
Im either missing something simple or making this more complicated than it needs to be. Once I find the matching Airport, I need to return the IATA code.
Which I envisage looking like this:
var OriginIATA = OriginAirport.IATA;
Im tired and feeling dumb. Please help :(
Since you declared all members of the Airport class as properties I assume you wanted to expose them publicly.
The error you get is because they are private members and can't be accessed outside the class.
Change "Airport" class to:
class Airport
{
public int Id { get; set; }
public string Name { get; set; }
public string LocationName { get; set; }
public string IATA { get; set; }
public string PortType { get; set; }
public string PortOwner { get; set; }
public string MotherPort { get; set; }
public bool Active { get; set; }
public bool IsApplyMeetAndGreet { get; set; }
public decimal MeetAndGreet { get; set; }
}
Having an issue with projection and getting child objects to load. The following is simplified code to represent the logic I'm trying to implement, not the actual code.
public class TicketItem
{
public int TicketItemId { get; set; }
public string TicketReason { get; set; }
public Station Station { get; set; }
public TicketOwner TicketOwner { get; set; }
}
public class Station
{
public int StationId { get; set; }
public string Name { get; set; }
}
public class TicketOwner
{
public int TicketOwnerId { get; set; }
public Employee Employee { get; set; }
public Organization Organization { get; set; }
}
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Organization
{
public int OrganizationId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class CommonReasons
{
public int CommonReasonId { get; set; }
public string Reason { get; set; }
}
public TicketItem GetById(int id)
{
var query = from i in _dataContext.TicketItems
.Include("Station")
.Include("TicketOwner.Employee")
.Include("TicketOwner.Organization")
join r in _dataContext.CommonReasons on i.TicketReason equals r.CommonReasonId.ToString() into r1
from r2 in r1.DefaultIfEmpty()
where i.TicketItemId == id
select new TicketItem {
TicketItemId = i.TicketItemId,
TicketReason = r2.Reason == null ? i.Reason : r2.Reason,
Station = i.Station,
TicketOwner = i.TicketOwner
};
return query
.AsNoTracking()
.FirstOrDefault();
}
Most the code is self-explanatory. The part that is indirectly causing the trouble would be the relationship between TicketItem.TicketReason property (a string) and the CommonReasons entity. From the user interface side, the end-user has an input field of "Reason", and they can select from "common" reasons or input an adhoc reason. They original developer chose to have the TicketReason property contain either the key ID from the CommonReasons table (if the user selected from drop-down) or the adhoc reason typed in.
So, to handle this logic in the linq query, the only way I have found is to do a left join between TicketItem.TicketReason and CommonReasons.CommonReasonId, then use projection to modify the TicketReason column returning either the common reason text or adhoc text. If there is a different way to do this that would get me around the trouble I'm having with projection/include, I'm all ears.
For the "reason" logic, this query works, returning the proper text. The trouble is that none of the "grand-child" objects are returning, i.e. TicketItem.TicketOwner.Employee, TicketItem.TicketOwner.Organization. How do I get those objects to return also?
Changing the structure of the tables would be an absolute last resort, just based on the amount of code that would have to change. There are other spots in the code that are using the above logic but don't need the child objects.
Any help would be appreciated. Hope I've explained enough.
I have table in a database that stores the following objects:
public class MyObjInfoWebView
{
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
public string Language { get; set; }
}
I also have a list of serial numbers, for example this:
var list = new List<string> {"010719/522", "010719/523", "010719/524", "010719/525", "010719/526"}
Is it possible to write (and how) LINQ query to filter objects from the table according to the available list of serial numbers and the required language?
This request solved my problem
_contex.InfoWeb.Where(x => list.Contains(x.SerialNumber) && x.Language == lang).ToListAsync();
I have 2 entities, with a 1 to many relationship, and I'm going to switch it to many to many but I need help with grouping and counts.
SearchString -> many JobResults
A SearchSting is used to find job results and job results are stored as a collection property of SearchString:
public class SearchString
{
public int SearchStringId { get; set; }
public string SearchStringName { get; set; }
public string query { get; set; }
public JobFunction JobFunction { get; set; }
public JobSeniority JobSeniority { get; set; }
public virtual ICollection<JobSearchResult> results { get; set; }
}
public class JobSearchResult
{
public int JobSearchResultId { get; set; }
public string jobtitle { get; set; }
public string company { get; set; }
public virtual SearchString SearchString { get; set; }
}
I get the top 5 JobFunctions of all job results as follows:
var top5jobfunctions = JobSearchResults.Where(a => (a.SearchString != null)).
GroupBy(s => new { s.SearchString.JobFunction.JobFunctionId, s.SearchString.JobFunction.JobFunctionName }).
Select(g => new { value = g.Key.JobFunctionId, displayname = g.Key.JobFunctionName, count = g.Count() }).
OrderByDescending(x => x.count).
Take(5).ToList();
I'm going to switch it to many to many as such:
public class SearchString
{
public int SearchStringId { get; set; }
public string SearchStringName { get; set; }
public string query { get; set; }
public JobFunction JobFunction { get; set; }
public JobSeniority JobSeniority { get; set; }
public virtual ICollection<JobSearchResult> results { get; set; }
}
public class JobSearchResult
{
public int JobSearchResultId { get; set; }
public string jobtitle { get; set; }
public string company { get; set; }
public virtual ICollection<SearchString> SearchStrings { get; set; }
}
How do I get my top 5 jobfunctions counts once I switch it to many to many?
Also, is the structure I chose the right approach? For example I wonder if having jobresults a child collection of SearchString was maybe not the best way to go and that perhaps I should just have SearchStrings be a collection property of JobResult.
For the modified model with many many relationship, consider the following modification to your original query:
var top5jobfunctions =
JobSearchResults.SelectMany(j => j.SearchString.Select(s => new {j,s}))
.Where(j => (j.s != null))
.GroupBy(j => new { j.s.JobFunction.JobFunctionId, j.s.JobFunction.JobFunctionName })
.Select(g => new { value = g.Key.JobFunctionId, displayname = g.Key.JobFunctionName, count = g.Count() })
.OrderByDescending(x => x.count)
.Take(5).ToList();
Explanation:
Now since JobSearchResult contains ICollection<SearchString>, it needs flattening to execute a similar query as earlier
SelectMany flattens the data and fills the results as an anonymous type, which contains a record for each SearchString
Henceforth similar logic as you have designed is followed
Model Correctness
I would not prefer, this kind of relationship, as it makes overall querying and data insertion unnecessarily complex
In my understanding a 1 to Many relationship would do as good a job in fetching all the relevant information, in this case you may consider just having ICollection<JobSearchResult> aggregated inside SearchString or vice versa relationship based on suitability, I am not sure what kind of use case does a circular many many relationship model solve.
I'm trying to get the count of a dictionary's value collection, where a field of the collection item, matches the key in the collection, as well as the type.
So my collection looks like this, note the object is initialized, this is just pseudo code:
var results = Dictionary<string, List<CourseEnrollmentsByStudentSQLResult>();
Now the CourseEnrollmentsByStudentSQLResult is a data transfer object, that maps to the rows returned from my query.
public class CourseEnrollmentsByStudentSQLResult
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string College { get; set; }
public int CollegeId { get; set; }
public string Prefix { get; set; }
public string CourseNumber { get; set; }
public string Course { get; set; }
public int CourseId { get; set; }
public string Program { get; set; }
public string Term { get; set; }
public string Status { get; set; }
public List<StudentCoursesSQLResult> Courses { get; set; }
}
You will notice that my CourseEnrollmentsByStudentSQLResult class also has a collection of StudentCoursesSQLResult objects. This is the list I'm trying to get a count of, based on two conditions.
First that the course, which is the string KEY in the dictionary, matches the course of the StudentCoursesSQLResult and then I need to filter on the StudentCoursesSQLResult.Type.
Here is the StudentCoursesSQLResult class:
public class StudentCoursesSQLResult
{
public int StudentID { get; set; }
public int Position { get; set; }
public string Prefix { get; set; }
public string CourseNumber { get; set; }
public string Course { get; set; }
public string Type { get; set; }
}
Now to get the count I'm looping over my dictionary and outputting headers for each key, this is where I'm trying to output the count for the dictionary's value collection.
foreach(var result in results) {
<span class="label label-default label-fat">
#result.Value.SelectMany(r => r.Courses).Count(c => c.Course == result.Key && c.Type == "required")
</span>
}
But for some reason it's returning zero, when I know it shouldn't be.
Can someone please point me in the right direction? Everything I've found so far online has said to use SelectMany, but I'm not having any luck.
Here is a screenshot of the debug output for a single course for the dictionary's value collection, where the Type is "required".
Looking at your screen shot, "Advanced French I: Structure and Expression" doesn't match the key of "Medieval Art and Architecture", which explains the incorrect count.
Instead, filter the CourseEnrollmentsByStudentSQLResult collection to those matching the dictionary key, then select all courses in those matched records, and finally count the courses that are "required".
#result.Value.Where(r => r.Course == result.Key)
.SelectMany(r => r.Courses)
.Count(c => c.Type == "required");
A variation on vivat if you want to do this in a program:
var cnt = selections.Where(r => r.Key == "Items").SelectMany(r => r.Value).Count();
"Items" is the Key value within the collection. In my case I created this collection:
Dictionary<string, string[]> selections = new Dictionary<string, string[]>();
Then added a simple set of values based on a key:
selections.Add("Items", txtItems.Text.Replace("\n", "").Split('\r'));
Later on I wanted to check if there had been any values set so I used the above method to count. It works great and in initial testing it helped me discover I needed to cleanup text entries before setting them up.