Print linq query (select *l) - c#

i need to print all rows from one table.
avoid placing: s.Adress+s.EmployeeID, etc
var query = from x
in bd.Employees
where x.City == "London" && x.TitleOfCourtesy == "Mr."
select x;
foreach(var s in query)
{
Console.WriteLine(s.Address+"---"+s.EmployeeID);
}

Console.WriteLine takes params so you can do this:
Console.WriteLine("{0}---{1}", s.Address, s.EmployeeID.ToString());
Or you can use C# 6.0 string interpolation (Note the dollar sign):
Console.WriteLine($"{s.Address}---{s.EmployeeID}");
EDIT
Since you mentioned in the comments:
I want to print all rows from each column from table Employees (Northwind db), without writing each of the columns names
You can do this, imagine you have a class:
public class One
{
public int Id { get; set; }
public string Name { get; set; }
}
You can:
// using System.Web.Script.Serialization;
var ser = new JavaScriptSerializer();
var one = ser.Serialize(new One() { Id = 1, Name = "George" });
Console.WriteLine(one);

Related

How to Right Join two Json files in C#?

I want to join two json files using a common key and get all the records from the right file and matching data from the left.
If it was SQL.
SELECT json1.CategoryDescription, json2.CategoryID, json2.TechName, json2.SpawnID
FROM json1
RIGHT JOIN json2
ON json1.CategoryID = json2.CategoryID
WHERE GameVersion = "A" OR GameVersoion = "2" AND CategoryID = "metals"
I need to get all the json2 records and the json1.CategoryDescription for each of them. But at the moment it just lists all the records from json1 then all the records from json2.
Here is my current attempt:
using System;
using System.IO;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
namespace ConsoleApp1
{
public class Program
{
public static void Main()
{
// Filter variables
var gameVer = "2";
var cat = "metals";
// Load the categories.json
JObject catObj = JObject.Load(new JsonTextReader(File.OpenText("D:/Code/Tests/categories.json")));
// Load the techtype.json
JObject ttObj = JObject.Load(new JsonTextReader(File.OpenText("D:/Code/Tests/techtypes.json")));
// Read techtype.json into an array
var mergeSettings = new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Union
};
catObj.Merge(ttObj, mergeSettings);
// Does not work,
/*
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at ConsoleApp1.Program.Main() in D:\Code\Tests\ReadTechTypes\ReadTechTypes\Program.cs:line 30
*/
// (catObj.SelectToken("Categoris") as JArray).Merge(ttObj.SelectToken("TechType"), mergeSettings);
// Does not work, same error
//var mergedArray = catObj.SelectToken("Categoris") as JArray;
//string json = mergedArray.ToString();
Console.WriteLine(catObj);
}
}
}
The left json
{
"Categories":[
{
"CategoryID":"baseupgrades",
"CategoryDescription":"Base Upgrades",
"IncludeCategory":true,
"GameVersion":"A"
},
{
"CategoryID":"batteries",
"CategoryDescription":"Batteries",
"IncludeCategory":true,
"GameVersion":"A"
},
{
"CategoryID":"blueprint",
"CategoryDescription":"Blueprint",
"IncludeCategory":false,
"GameVersion":"A"
}
// Other category values omitted
]
}
The right json
{
"Items":[
{
"CategoryID":"crystalline",
"TechName":"Quartz",
"SpawnID":"quartz",
"TechID":1,
"GameVersion":"A"
},
{
"CategoryID":"metals",
"TechName":"Metal Salvage",
"SpawnID":"scrapmetal",
"TechID":2,
"GameVersion":"A"
},
{
"CategoryID":"outcrop",
"TechName":"Limestone Outcrop",
"SpawnID":"limestonechunk",
"TechID":4,
"GameVersion":"A"
}
// Other items omitted
]
}
Any ideas?
You can try this
categoriesRoot = JsonConvert.DeserializeObject<CategoriesRoot>(categoriesJson);
itemsRoot = JsonConvert.DeserializeObject<ItemsRoot>(itemsJson);
var items = from cr in categoriesRoot.Categories
join ir in itemsRoot.Items on cr.CategoryID equals ir.CategoryID into irj
from ir in irj.DefaultIfEmpty()
where ( (cr.GameVersion == "A") || (cr.GameVersion == "2" && cr.CategoryID == "metals"))
select new {
cr.CategoryDescription,
ir.CategoryID,
ir.TechName,
ir.SpawnID
};
var newItemsJson=JsonConvert.SerializeObject(items);
after creating these classes
public class Item
{
public string CategoryID { get; set; }
public string TechName { get; set; }
public string SpawnID { get; set; }
public int TechID { get; set; }
public string GameVersion { get; set; }
}
public class ItemsRoot
{
public List<Item> Items { get; set; }
}
public class Category
{
public string CategoryID { get; set; }
public string CategoryDescription { get; set; }
public bool IncludeCategory { get; set; }
public string GameVersion { get; set; }
}
public class CategoriesRoot
{
public List<Category> Categories { get; set; }
}
output will be like this
[
{"CategoryDescription":"Base Upgrades","CategoryID":"crystalline","TechName":"Quartz","SpawnID":"quartz"},
{"CategoryDescription":"Batteries","CategoryID":"metals","TechName":"Metal Salvage","SpawnID":"scrapmetal"}
]
And by the way you have a bug in your SQL query
WHERE GameVersion = "A" OR GameVersoion = "2" AND CategoryID = "metals"
this is an ambiguous code, since there are GameVersion and CategoryID in both queries.
The following should work:
// Filter variables
var gameVersions = new HashSet<string> { "A", "2" };
var categoryIDs = new HashSet<string> { "metals" };
// Left outer join on ttObj. Select all Items[*] array items
var query = from i in ttObj.SelectTokens("Items[*]").OfType<JObject>()
// Filter on the game version and category ID
let categoryId = (string)i["CategoryID"]
let gameVersion = (string)i["GameVersion"]
where categoryIDs.Contains(categoryId) && gameVersions.Contains(gameVersion)
// Join with "Categories[*]" on category ID
join c in catObj.SelectTokens("Categories[*]") on categoryId equals (string)c["CategoryID"] into joined
// DefaultIfEmpty makes this a left join
from cat in joined.DefaultIfEmpty()
// Select all records of i and add the CategoryDescription from cat.
select new JObject(i.Properties()) { new JProperty("CategoryDescription", cat?["CategoryDescription"]) };
var results = query.ToList(); // Materialize the query into a list of results.
Which results in:
[
{
"CategoryID": "metals",
"TechName": "Metal Salvage",
"SpawnID": "scrapmetal",
"TechID": 2,
"GameVersion": "A",
"CategoryDescription": null
}
]
Notes:
I changed the query from a right join to a left join because it made the filtering look a little more natural. See LINQ Left Join And Right Join if you would prefer the right join syntax.
The final select statements creates a new JObject with all the records from the JObject i item object then adds the CategoryDescription from the cat category object. It does not modify the existing object i.
JContainer.Merge() isn't going to help you here because it doesn't have any ability to merge based on some primary key.
ttObj.SelectTokens("Items[*]") uses the JSONPath wildcard operator [*] to select all items in the "Items" array.
As there is no category with "CategoryID":"metals", cat is null in the ultimate select statement.
Demo fiddle here.
The problem is that you are merging the "Category" list with the "Items" list, and "Items" is not present on catObj.
[I suggest to you to convert the items in class (with visual studio you can do a "Special paste" as JSON class).]
You have to iterate over the items of the first list and merge with the corresponding element in the second list, member with member, not list with list.

Select columns from table based on column names from another table

At the beginning I am aware that there are similar questions, but mine is a little bit different.
I implemented a function that allows the user to select the columns he wants to see.
I've created a stored procedure that gets all column names from the UserColumns table, creates a dynamic sql query and then runs the exec (#command) query. The functionality described above works very well, but there are more requirements that I can't handle this way.
There is TasksViewModel:
public class TasksViewModel
{
public List<Dictionary<List<string>, List<List<object>>>> Tasks { get; set; }
public List<UserDefaultStatusesViewModel> UserStatuses { get; set; }
public List<ZgloszenieStatus> TaskStatuses { get; set; }
public TasksViewModel()
{
}
}
Tasks is filled by stored procedure that runs SELECT x,y,z... FROM table... query.
I'm using this method:
private static IEnumerable<Dictionary<List<string>, List<List<object>>>> Read(DbDataReader reader)
{
var dict = new Dictionary<List<string>, List<List<object>>>();
var cols = new List<string>();
for (int temp = 0; temp < reader.FieldCount; temp++)
{
cols.Add(reader.GetName(temp));
}
var items = new List<List<object>>();
while (reader.Read())
{
var tmp = new List<object>();
for (int i = 0; i < reader.FieldCount; i++)
{
tmp.Add(reader.GetValue(i));
}
items.Add(tmp);
}
dict.Add(cols, items);
foreach (var item in dict)
{
}
yield return dict;
}
I find this very overcomplicated, but at the moment I have no idea if there is another way to do this.
I'm using Entity Framework in my application.
Imagine that I'm using List<Tasks> instead of List<Dictionary<List<string>, List<List<object>>>>. Tasks is database table.
public class Tasks
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime Date { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
User wants to see only ID,Title,Description columns, so the UserColumns table looks like this:
UserId | ColumnName
1 | ID
2 | Title
3 | Description
Is there a way to select specific columns from List<Tasks> based on UserColumns table using Entity Framework ?
You can create the lambda for Column List dynamically
static Func<Tasks, Tasks> CreateSelect(string[] columns)
{
var parameterExpression = Expression.Parameter(typeof(Tasks), "p");
var newExpression = Expression.New(typeof(Tasks));
var bindings = columns.Select(o => o.Trim())
.Select(o =>
{
var pi = typeof(Tasks).GetProperty(o);
var memberExpression = Expression.Property(parameterExpression, pi);
return Expression.Bind(pi, memberExpression);
}
);
var memberInitExpression = Expression.MemberInit(newExpression, bindings);
var lambda = Expression.Lambda<Func<Tasks, Tasks>>(memberInitExpression, parameterExpression);
return lambda.Compile();
}
and create a LINQ query based on that lambda (columnNameList array is rows from UserColumns table)
static void Foo()
{
var columnNameList = new string[] { "ID", "Title", "Description" };
var tasksList = new List<Tasks>
{
new Tasks{ ID=1, Title="T1", FirstName="F1", LastName="L1", Description="D1", Date=DateTime.UtcNow },
new Tasks{ ID=2, Title="T2", FirstName="F2", LastName="L2", Description="D2", Date=DateTime.UtcNow }
};
var tasks = tasksList.Select(CreateSelect(columnNameList)).FirstOrDefault();
}
I hope that answers your question.

Set the first Record Value of LINQ

I have a DBSet which is db.Company and it contains 3 records like
id name is_active
1 company1 1
2 company2 1
3 company3 1
My Created class to transfer the records:
public class CompanyFinal
{
public int id { get; set; }
public string name { get; set; }
public string selected { get; set; }
}
My LINQ looks like this:
(from h in db.Company where h.is_active == 1 select new CompanyFinal { id = h.id, name = h.name, selected = "false" }).ToList();
No doubt this LINQ is working but i need to make the first record to be selected="true" which is the company 1 while doing it in LINQ.
How could i do that? Is it possible?
Thanks in advance
Since you're making a list, I think that computational the fasted method, which is also the best maintainable (understood by others) would be to just assign the first element:
(Using method syntax, showing an alternative select)
var resultingList = db.Company
.Where(company => company.is_active == 1)
.Select(company => new CompanyFinal()
{
id = company.id,
name = company.name,
selected = "false",
})
.ToList();
if (resultingList.Any())
resultingList[0].selected = true;
If you are not sure whether you want to convert it to a list, for instance because you want to concatenate other Linq functions after it, consider using this overload of Enumerable.Select
var result = db.Company
.Where(company => company.is_active == 1)
.Select( (company, index) => new CompanyFinal()
{
id = company.id,
name = company.name,
selected = (index == 0) ? "true" : "false",
});
By the way, consider changing your CompanyFinal class such that selected is a bool instead of a string, that would make your code less error prone. For instance, after construction Selected is neither "true" nor "false". Users are able to give it a value like "TRUE" or String.Empty
If your class has users that really need a string property selected instead of a Boolean property consider keeping a get property for it:
public class CompanyFinal
{
public int id { get; set; }
public string name { get; set; }
public bool Selected {get; set;}
// for old user compatability:
public string selected
{
get { return this.Selected ? "true" : "false"; }
}
}
The following will go wrong:
if (companyFinals[0].selected == "True") ...
versus:
if (companyFinals[0].Selected)
What if we define a local variable
var counter = 1;
(from h in db.Company where h.is_active == 1 select new CompanyFinal { id = h.id, name = h.name, selected = (counter++ == 1 ? "true" :"false") }).ToList();
From your result:
var companies = (from h in db.Company
where h.is_active == 1 select h).ToList();
var companyFinals = (from h in companies
select new CompanyFinal {
id = h.id,
name = h.name,
selected = "false"
}).ToList();
var firstCompany = companies.FirstOrDefault();
if (firstCompany != null) {
firstCompany.selected = true;
}
// save result back to database
There is no way to do it in 1 operation other than writing a stored procedure.

Linq returning different result than SQL

I'm running this Linq query:
var patientList = from p in db.Patients
where p.ClinicId==11
select p.Id;
var patientswithplan = from p in db.Plans
where patientList.Contains(p.PatientId)
select p;
It returns 1030 results.
But when I came up with this query I wrote it in sql first to test it out and this displays 956 results
select id from patients where clinicid=11
and id in(select patientid from plans)
order by id
I thought these queries would be the same, what is the difference, which one is correct?
I have written a little code then you could see the difference yourself
void Main()
{
var Plans = new List<Plan>();
Plans.Add(new Plan() {PatientId = 1, PlanName = "Good Plan"});
Plans.Add(new Plan() {PatientId = 2, PlanName = "Bad Plan"});
var Patients = new List<Patient>();
Patients.Add(new Patient() {ClinicId = 1, Name = "Frank"});
Patients.Add(new Patient() {ClinicId = 2, Name = "Fort"});
// This is your LINQ
var patientList = from p in Patients
where p.ClinicId == 1
select p.ClinicId;
var patientswithplan = from p in Plans
where patientList.Contains(p.PatientId)
select p;
Console.WriteLine(patientswithplan);
// We return a PLAN here
// Result
// IEnumerable<Plan> (1 item)
// PatientId 1
// PlanName Good Plan
// This is the equivalent Linq of your SQL
var myPatient = Patients.Where(
pa => pa.ClinicId == 1 &&
Plans.Any(pl => pl.PatientId == pa.ClinicId)
);
Console.WriteLine(myPatient);
// Look! We return a PATIENT here
// Result
// IEnumerable<Patient> (1 item)
// ClinicId 1
// Name Frank
}
// Define other methods and classes here
class Patient
{
public Patient() {}
public int ClinicId { get; set; }
public string Name { get; set; }
}
class Plan
{
public Plan() {}
public int PatientId { get; set; }
public string PlanName { get; set; }
}
The queries do two different things:
1) The first query is basically first getting a list of patients, and then it's fetching plans (you choose "from p in db.Plans") that have those selected patients in their list of patients.
2) The second query is filtering and fetching patients of given clinic making sure that those patients exist in some plans.
So of course the number of results will be different as you probably have a different number of rows in the patients and plans tables.

parse a string with name-value pairs

How can I parse the following string of name-value pair in C#:
string studentDetail = "StudentId=J1123,FirstName=Jack,LastName=Welch,StudentId=k3342,FirstName=Steve,LastName=Smith"
The purpose of parsing this array is to insert values in DB using Linq to SQL:
[HttpPost]
public ActionResult SaveStudent(string studentDetail)
{
DataContext db = new DataContext();
Student student = new Student();
{
student.StudentID = //StudentID
student.FirstName = //FirstName
student.LastName = //LastName
};
db.Student.InsertOnSubmit(student);
db.SubmitChanges();
return View();
}
What is the best way of approaching this?
You can split on the comma, then on the equals sign. I put the data into a dictionary for easy access.
string input = "StudentId=J1123,FirstName=Jack,LastName=Welch";
Dictionary<string,string> keyValuePairs = input.Split(',')
.Select(value => value.Split('='))
.ToDictionary(pair => pair[0], pair => pair[1]);
string studentId = keyValuePairs["StudentId"];
Note that this isn't validating the input at all to ensure that there are no commas in values, no keys without values, missing keys, etc.
Because the individual student records are not delimited in the input, I would do something like the following:
public class Student
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
and then:
private List<Student> DoSplit(string input)
{
var theReturn = new List<Student>();
input = input.Replace(",StudentId=", "|,StudentId=");
var students = input.Split('|');
foreach (var student in students)
{
var attribs = student.Split(',');
if (attribs.Count() == 3)
{
var s = new Student();
s.Id = attribs[0].Substring(attribs[0].LastIndexOf('='));
s.FirstName = attribs[1].Substring(attribs[1].LastIndexOf('='));
s.LastName = attribs[2].Substring(attribs[2].LastIndexOf('='));
theReturn.Add(s);
}
}
return theReturn;
}
Again, it's a bit naive because if content contains "=", ",", or "|", there will be failures. You should add some checking in there as well.
Eric Petroelje had a very nice answer at https://stackoverflow.com/a/2049079/59996
Try System.Web.HttpUtility.ParseQueryString, passing in everything
after the question mark. You would need to use the System.Web
assembly, but it shouldn't require a web context.
(I'm not sure why these two questions aren't linked)
I was able to parse a string of the form a=1&b=2&c=3 using the following code
NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(submission);

Categories

Resources