Building a LINQ query based on a JSON array - json

imagine the JSON array to have a list of key-value pairs.
<search_parameter>: <value>
...
name: "John"
age:"20"
dept: "Development"
...
Now, I want to dynamically query the employee list based on the key-value pairs I receive. For each time, I receive a different number of key-value pairs.
I may receive name alone sometimes and I may receive age as well at times. It could be just the dept at times.

without knowing details I would say you can easily add where predicates on your linq query based on the available filters.
public class InputFilters
{
public string name { get; set; }
public string age { get; set; }
public string dept { get; set; }
}
let's say variable input has search parameters.
then linq would be
var result = from emp in _context.Employees
select emp;
if(!string.IsNullOrEmpty(input.name))
result = result.where(e => e.name == input.name);
if(!string.IsNullOrEmpty(input.age))
result = result.where(e => e.age == input.age);
if(!string.IsNullOrEmpty(input.dept))
result = result.where(e => e.dept == input.dept);

Related

SQL query with group by and where filtering a received parameter

I'm trying to do in Linq EF this my sql query:
SELECT date FROM tab_4009_atv
WHERE id_asset IN ['ako','bj89','flity76']
GROUP BY date;
but there's a specific situation.
This list that I'm filtering is received as a parameter like this:
public async Task<IEnumerable< Date>> getDates (IEnumerable< string>assetList){ }.
How can I do this? Thanks!
The SQL query and the C# method signature you have given don't really fit each other. SQL query returns a grouping of dates, but the C# method returns a list of dates. We need to modify the return type of the method.
On the other hand, this question is more about converting the string to the Asset object than SQL or LINQ. Since we do not know what the Asset object looks like we cannot help you with that conversion. We have to delegate that responsibility to another method.
Additionally, the method doesn't need to be async.
The following code should do what you are looking for.
public class Asset
{
public DateTime Date { get; set; }
public string? OtherData { get; set; }
}
private static Asset StringToDate(string assetString)
{
// Convert string to asset object
}
public IEnumerable<IGrouping<DateTime, Asset>> GetDates(IEnumerable<string> assetList)
{
var filter = new[] {"ako", "bj89", "flity76"};
var dates = assetList
.Where(x => filter.Contains(x))
.Select(x => StringToDate(x))
.GroupBy(assets => assets.Date);
return dates;
}

LINQ Webservice GET list of similar products from JSON file

I am loading a JSON file from a storage, that file hold similar products. One product can have multiple similar products. What i want to do is read the contents of the JSON file from the storage (code is de filename in this case: 458755), search in that file for a matching id_product and if that id_product if found return the list of the similar products. This is what i got so far:
string uriPath = "https://xxxx.blob.core.windows.net/";
public object GetSimilarProducts(string Code, int id_product)
{
string secondPart = "api/SimilarProducts/" + Code + ".json";
var allSimilarProducts = (new WebClient()).DownloadString(uriPath + secondPart);
object jsonObject = JsonConvert.DeserializeObject(allSimilarProducts);
var all = allSimilarProducts
.Where(a => a.id_product == id_product)
.ToList();
return all;
}
This is a content sample of the SimilarProducts.json file: 458755.json
[
{"id_product":33681,"Brand":"Ikea","Product":"STOCKHOLM Tv-meubel"},
{"id_product":33681,"Brand":"Ikea","Product":"STOCKHOLM Kast"},
{"id_product":33685,"Brand":"Ikea","Product":"EKENÄS Fauteuil"}
]
where it goes wrong is with the a =>.a_id_product because that normally reads from a database table. How would i be able to do this? Search in the JSON file and get all the two similar products of 33681 and output them as a list?
Create a class for your products and then use Newtonsoft's JsonConvert.Deserialize to deserialize them in to a list of your products.
Here is a working DotNetFiddle and code below:
Then you can complete your query for your results:
public List<Products> GetSimilarProducts(string Code, int id_product)
{
var json = #"[{ 'id_product':33681,'Brand':'Ikea','Product':'STOCKHOLM Tv-meubel'},
{'id_product':33681,'Brand':'Ikea','Product':'STOCKHOLM Kast'},
{ 'id_product':33685,'Brand':'Ikea','Product':'EKENÄS Fauteuil'}]";
(...other)
var products = JsonConvert.DeserializeObject<List<Products>>(json);
var all = products.Where(a => a.IdProduct == id_product).ToList();
return all;
}
public class Products
{
[JsonProperty("id_product")]
public int IdProduct {get;set;}
[JsonProperty("Brand")]
public string Brand { get; set; }
[JsonProperty("Product")]
public string Product { get; set; }
}
Results:

Linq-2-SQL Concat or Union Different types

I am trying to concatenate IQueryable where T can be different types.
So ((IQueryable<Person>)people).Concant((IQueryable<Account>)accounts).
I have created a structure like so:
public struct PerformanceStructure
{
public Entity Entity { get; set; }
public Entity Performance { get; set; }
}
I am building dynamic queries that follow this template:
var result = context.Accounts.Where(a => a.id == 1).Select(s => new PerformanceStructure { Entity = s });
result = result.Concat(context.Person.Where(p => p.id = 1).Select(s => new PerformanceStructure {Entity = s});
Execution looks like this:
var list = result.Skip(pageSize * (pageNumber - )).Take(pageSize);
When executing the query, I get the error Types in Union or Concat have different members assigned
What can I do to resolve this error but retrieve the two objects from that database?
In the end I want to paginate the query (thus the skip/take) based on some order.

Entity Framework Raw SQL with relational entities

I recently started experimenting with Raw SQL using Entity Framework, and I prefer it in some cases.
I would like to know if there is a way to grab relational entities:
Dosnt work:
var personNo = context.Person.SqlQuery("SELECT * FROM `Person` LIMIT 1").FirstOrDefault();
foreach(var Number in personNo.Phone) {
//never iterates
}
Works (but LINQ-to-Entities which I dont want in this case):
var personNo = context.Person.FirstOrDefault();
foreach(var Number in personNo.Phone) {
//iterate twice as it contains in the db
}
I tried a couple of different queries including
SELECT * FROM `Person` LEFT JOIN `Phone` ON (`Person`.ID = `Phone`.PersonID) LIMIT 1
What is the correct way to write the query on to recieve the list of Phone numbers? Is this possible?
You can do SQL to entities. I prefer this way when I have joins and group bys in them, and don't have permission to create a view.
First, create a class and add properties with the same names as the returned columns.
public class PersonWithAddress
{
public int Id { get; set; }
public String Name { get; set; }
public String Address { get; set; }
}
And the C# with parameters
MyEntity db = new MyEntity();
String sqlQuery = #"
SELECT Id, Name, Address
FROM Person p
JOIN Address a
ON a.Id = p.Id
WHERE Name = #Name
AND Address = #Address
";
String searchName = "Joe";
String address = "123 Something Lane";
DbRawSqlQuery<PersonWithAddress> results = db.Database.SqlQuery<PersonWithAddress>(
sqlQuery,
new SqlParameter("#Name", searchName),
new SqlParameter("#Address", address)
);
foreach(PersonWithAddress a in results)
{
}
You can list as many parameters as you want.
Wow this question's 2 years old. I didn't even realize that.

Create an entity for a 'many to many' mapping table Code First

I will start by saying this may not be conceptually correct so I will post my problem also, so if someone can help with the underlying problem I won't need to do this.
Here is a simplified version of my model.
public class MenuItem
{
public int MenuItemId { get; set; }
public string Name { get; set; }
public virtual ICollection<Department> Departments { get; set; }
private ICollection<MenuSecurityItem> _menuSecurityItems;
public virtual ICollection<MenuSecurityItem> MenuSecurityItems
{
get { return _menuSecurityItems ?? (_menuSecurityItems = new HashSet<MenuSecurityItem>()); }
set { _menuSecurityItems = value; }
}
}
public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
public virtual ICollection<MenuItem> MenuItems { get; set; }
}
My underlying problem is that I want to select all MenuItems that belong to a Department (Department with DepartmentId = 1 for arguments sake) and also include all MenuSecurityItems.
I am unable to Include() the MenuSecurityItems as the MenuItems navigation collection is of type ICollection and doesn't support Include(). This also doesn't seem to work Department.MenuItems.AsQueryable().Include(m => m.MenuSecurityItems)
The way I "fixed" this issue was creating an entity for the many-to-many mapping table Code First creates.
public class DepartmentMenuItems
{
[Key, Column(Order = 0)]
public int Department_DepartmentId { get; set; }
[Key, Column(Order = 1)]
public int MenuItem_MenuItemId { get; set; }
}
I then was able to join through the mapping table like so. (MenuDB being my DBContext)
var query = from mItems in MenuDb.MenuItems
join depmItems in MenuDb.DepartmentMenuItems on mItems.MenuItemId equals depmItems.MenuItem_MenuItemId
join dep in MenuDb.Departments on depmItems.Department_DepartmentId equals dep.DepartmentId
where dep.DepartmentId == 1
select mItems;
This actually worked for that particular query... however it broke my navigation collections. Now EF4.1 is throwing an exception as it is trying to find an object called DepartmentMenuItems1 when trying to use the navigation collections.
If someone could either help me with the original issue or the issue I have now created with the mapping table entity it would be greatly appreciated.
Eager loading of nested collections works by using Select on the outer collection you want to include:
var department = context.Departments
.Include(d => d.MenuItems.Select(m => m.MenuSecurityItems))
.Single(d => d.DepartmentId == 1);
You can also use a dotted path with the string version of Include: Include("MenuItems.MenuSecurityItems")
Edit: To your question in comment how to apply a filter to the MenuItems collection to load:
Unfortunately you cannot filter with eager loading within an Include. The best solution in your particular case (where you only load one single department) is to abandon eager loading and leverage explicite loading instead:
// 1st roundtrip to DB: load department without navigation properties
var department = context.Departments
.Single(d => d.DepartmentId == 1);
// 2nd roundtrip to DB: load filtered MenuItems including MenuSecurityItems
context.Entry(department).Collection(d => d.MenuItems).Query()
.Include(m => m.MenuSecurityItems)
.Where(m => m.Active)
.Load();
This requires two roundtrips to the DB and two queries but it's the cleanest approach in my opinion which actually only loads the data you need.
Other workarounds are 1) either to apply the filter later in memory (but then you have to load the whole collection first from the DB before you can filter) or 2) to use a projection. This is explained here (the second and third point):
EF 4.1 code-first: How to order navigation properties when using Include and/or Select methods?
The examples in this answer are for ordering but the same applies to filtering (just replace OrderBy in the code snippets by Where).