Loop through table of datacontext - c#

What I would like to do is, loop through a datacontext and for each table found, select two different rows and compare the individual columns and see if the rows are equal.
So far I've made a method to compare the values of two rows and return true if all values of the rows are equal.
Now I would like to put this method into a foreach loop along the lines outline below:
using (DataClassesDataContext db = new DataClassesDataContext(Utillities.dbconnection))
{
foreach (Table t in db)
{
var row1 = from r1 in t where r1.id == constraint1 select;
var row2 = from r2 in t where r2.id == constraint2 select;
bool compResult = CompareRows(row1, row2);
}
}
But I don't know how to construct the foreach loop, so I can make the above selections :(
I've tried db.Mapping.GetTables(), but I can't see how this gets me closer - I can only get the table-names in the datacontext, not the tables themselves. Are there a way to get a table entity from a string containing the tablename? Or am I missing something (likely something obvious)?
Any help or hints with the above foreach loop will be much appreciated.

This will not work unless you implement CompareRows for every combination of te possible types available. You cannot pas an anonymous type.
You can use this approach to get all the tables/columns
http://blogs.msdn.com/b/jomo_fisher/archive/2007/07/30/linq-to-sql-trick-get-all-table-names.aspx
I would create dynamic sql statements and use DB.Executequery insted

Related

Xamarin/C# - Insert data into SQLite database programmatically for multiple tables?

My Xamarin app pulls data from an API and inserts that data into a SQLite table. The API currently has 9 tables defined, and as such there are 9 classes in my app that match those tables. I used the code snippet from this question's accepted answer:
Getting all types in a namespace via reflection
Below is my code, using the snippet from the answer and the foreach loop I'm trying to build that'll insert the data.
string nspace = "App.Tables";
var q = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && t.Namespace == nspace
select t.Name; // Getting list of classes as IEnumerable
var L = q.ToList(); // Converting to List
foreach (var name in L) // Inserts data for every class found
{
var response = await httpClient.Value.GetStringAsync("http://website.com/api/" + name + "s"); // Substitutes each class name into API url
var data = JsonConvert.DeserializeObject<List<TableName>>(response); // Deserializes into List
using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation)) // Opens database connection
{
conn.CreateTable<TableName>(); // Create table
conn.DeleteAll<TableName>(); // Delete all old data
conn.InsertAll(data); // Inserts new data
}
}
I don't know what TableName should be in order to get the correct class for each item on the list. For example: say the list contained the strings Table1, Table2, and Table3 - it got those strings from the App.Tables namespace which contains three separate classes called Table1, Table2, and Table3. When the first part of the code gets the list and stores it as the variable L, it should get the data for each "name" variable in L and then insert it into the matching table. How do I refer it to the table?
Before I would give my answer, I would like to tell you that I do not
recommend updating tables via reflection - tables should contain
logically distinct entities, so batch deleting and updating them is
kinda weird. This is one of those few occurrences where I would never
work around typing the updates of the tables one by one. But those are
just my two cents... Of course if I had a thousand tables my opinion
would not stand.
This kind of reflection also makes your code hard to follow and trace - think about how you will search for usages of the CreateTable<ExampleClass>() method? You will never trace it back - or only via great efforts - that you called it in this piece of code.
So to answer your question...
You first get the method group, then create a generic version of it based on the type. I think converting from Type to string is unnecessary for the part you're looking for, since you need to convert back to Type
using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation)) {
MethodInfo nonGenMethodCreate = typeof(SQLiteConnection).GetMethod("CreateTable");
MethodInfo nonGenMethodDeleteAll = typeof(SQLiteConnection).GetMethod("DeleteAll");
MethodInfo nonGenMethodInsertAll = typeof(SQLiteConnection).GetMethod("InsertAll");
foreach(Type t in Assembly.GetExecutingAssembly.GetTypes()) {
MethodInfo genMethodCreate = nonGenMethodCreate.MakeGenericMethod(t);
MethodInfo genMethodDeleteAll = nonGenMethodDeleteAll.MakeGenericMethod(t);
MethodInfo genMethodInsertAll = nonGenMethodInsertAll.MakeGenericMethod(t);
genMethodCreate.Invoke(conn, null);
genMethodDeleteAll.Invoke(conn, null);
genMethodInsertAll.Invoke(conn, new[] { data });
}
}

How can I do a loop within a "boolean conditional statement"?

How can you put a loop within a conditional statement in C#? I have an example below where this could be useful in querying data for two reasons: it would avoid writing each item out or foreaching around the whole query, and it would avoid accessing the database for each item in the list if we assume the query is querying the database and we want to avoid the added hits to the database. So how can I loop within a conditional statement, like an if statement or a query statement. My take is that it would be pretty easy in a dynamic language like Ruby, but there's no easy way in C# or most static languages. Please let me know if I'm missing anything. Thanks.
List<string> certainTerritorysManagers = GetTerritoryManagers(east);
var AllSales= GetAllSales();
var EastTerritorySales = (from sale in AllSales
where sale.manager == manager1 || sale.manager == manager2 || ... etc.
// *** Is there a way I can stick a foreach loop in the line above so I don't have to list all of these managers?
// *** Pseudo code might look like: where sale.manager == ANYOF foreach (string manager in aCertainTerritoriesManagers)
// *** If it was all && statements intead of || statements you could use the term ALLOF
select sale).ToList();
I think you're looking for Contains:
var EastTerritorySales =
(from sale in AllSales
where certainTerritoryManagers.Contains(sale.manager)
select sale).ToList();
You could do something like:
var eastTerritorySales =
(from sale in AllSales
where certainTerritorysManagers.Contains(sale.manager)
select sale).ToList();
Given that certainTerritorysManagers is a list of strings, the sale.manager need to be a string.
So, if the manager is another class with properties, you will need to do something like:
where certainTerritorysManagers.Contains(sale.manager.Name)
I hope it helps!

Dynamic Linq Group By

I am currently building reports and have a need to Group columns dynamically, depending on user's choice. Now, assuming that the situation is fixed on all columns, the query would be as follows:
var groupedInvoiceItems = invoiceItems.GroupBy(x => new { x.SalesInvoice.name, x.SalesInvoice.currencyISO, x.CatalogProduct });
Doing so would return results as desired, IGrouping. I would then run a loop to process the necessary data as below:
foreach (var groupedInvoiceItem in groupedInvoiceItems)
{
// Perform work here
}
Now, the headache comes in when I try to make the Grouping dynamic by using Dynamic Linq. The query is as follows:
var groupedInvoiceItems = invoiceItems.GroupBy("new (SalesInvoice.name, SalesInvoice.currencyISO, CatalogProduct)", "it");
The problem with this is that it does not return IGrouping anymore. Hence, my foreach loop no longer works. Is there any solution to the matter? I tried casting IGrouping to the Dynamic query but to no avail. Help is needed urgently.
The result of the GroupBy is an IEnumerable<IGrouping<DynamicClass,InvoiceItem>>, so you can proceed by something like:
foreach (IGrouping<DynamicClass,InvoiceItem> invoiceItemGroup in groupedInvoiceItems)
{
}
You should do the grouping then select the specified attributes to iterate throw them in the foreach loop. Try this out:
var groupedInvoiceItems = invoiceItems.GroupBy("SalesInvoice.name","it").GroupBy("SalesInvoice.currencyISO","it").GroupBy("CatalogProduct","it").Select("new (it.SalesInvoice.name,it.SalesInvoice.currencyISO,it.CatalogProduct)");
Hope this works.

Using variables to build a LinQ query?

I don't think is possible but wanted to ask to make sure. I am currently debugging some software someone else wrote and its a bit unfinished.
One part of the software is a search function which searches by different fields in the database and the person who wrote the software wrote a great big case statement with 21 cases in it 1 for each field the user may want to search by.
Is it possible to reduce this down using a case statement within the Linq or a variable I can set with a case statement before the Linq statement?
Example of 1 of the Linq queries: (Only the Where is changing in each query)
var list = (from data in dc.MemberDetails
where data.JoinDate.ToString() == searchField
select new
{
data.MemberID,
data.FirstName,
data.Surname,
data.Street,
data.City,
data.County,
data.Postcode,
data.MembershipCategory,
data.Paid,
data.ToPay
}
).ToList();
Update / Edit:
This is what comes before the case statement:
string searchField = txt1stSearchTerm.Text;
string searchColumn = cmbFirstColumn.Text;
switch (cmbFirstColumn.SelectedIndex + 1)
{
The cases are then done by the index of the combo box which holds the list of field names.
Given that where takes a predicate, you can pass any method or function which takes MemberDetail as a parameter and returns a boolean, then migrate the switch statement inside.
private bool IsMatch(MemberDetail detail)
{
// The comparison goes here.
}
var list = (from data in dc.MemberDetails
where data => this.IsMatch(data)
select new
{
data.MemberID,
data.FirstName,
data.Surname,
data.Street,
data.City,
data.County,
data.Postcode,
data.MembershipCategory,
data.Paid,
data.ToPay
}
).ToList();
Note that:
You may look for a more object-oriented way to do the comparison, rather than using a huge switch block.
An anonymous type with ten properties that you use in your select is kinda weird. Can't you return an instance of MemberDetail? Or an instance of its base class?
How are the different where statements handled, are they mutually excluside or do they all limit the query somehow?
Here is how you can have one or more filters for a same query and materialized after all filters have been applied.
var query = (from data in dc.MemberDetails
select ....);
if (!String.IsNullOrEmpty(searchField))
query = query.Where(pr => pr.JoinDate.ToString() == searchField);
if (!String.IsNullOrEmpty(otherField))
query = query.Where(....);
return query.ToList();

Search in a List<DataRow>?

I have a List which I create from a DataTabe which only has one column in it. Lets say the column is called MyColumn. Each element in the list is an object array containing my columns, in this case, only one (MyColumn). Whats the most elegant way to check if that object array contains a certain value?
var searchValue = SOME_VALUE;
var result = list.Where(row => row["MyColumn"].Equals(searchValue)); // returns collection of DataRows containing needed value
var resultBool = list.Any(row => row["MyColumn"].Equals(searchValue)); // checks, if any DataRows containing needed value exists
If you should make this search often, I think it's not convenient to write LINQ-expression each time. I'd write extension-method like this:
private static bool ContainsValue(this List<DataRow> list, object value)
{
return list.Any(dataRow => dataRow["MyColumn"].Equals(value));
}
And after that make search:
if (list.ContainsValue("Value"))
http://dotnetperls.com/list-find-methods has something about exists & find.
Well, it depends on what version C# and .NET you are on, for 3.5 you could do it with LINQ:
var qualiyfyingRows =
from row in rows
where Equals(row["MyColumn"], value)
select row;
// We can see if we found any at all through.
bool valueFound = qualifyingRows.FirstOrDefault() != null;
That will give you both the rows that match and a bool that tells you if you found any at all.
However if you don't have LINQ or the extension methods that come with it you will have to search the list "old skool":
DataRow matchingRow = null;
foreach (DataRow row in rows)
{
if (Equals(row["MyColumn"], value))
{
matchingRow = row;
break;
}
}
bool valueFound = matchingRow != null;
Which will give you the first row that matches, it can obviously be altered to find all the rows that match, which would make the two examples more or less equal.
The LINQ version has a major difference though, the IEnumerable you get from it is deferred, so the computation will not be done until you actually enumerate it's members. I do not know enough about DataRow or your application to know if this can be a problem or not, but it was a problem in a piece of my code that dealt with NHibernate. Basically I was enumerating a sequence which members where no longer valid.
You can create your own deferred IEnumerables easily through the iterators in C# 2.0 and higher.
I may have misread this but it seems like the data is currently in a List<object[]> and not in a datatable so to get the items that match a certain criteria you could do something like:
var matched = items.Where(objArray => objArray.Contains(value));
items would be your list of object[]:s and matched would be an IEnumerable[]> with the object[]:s with the value in.

Categories