Can LINQ To SQL detect where a table association breaks? - c#

I have two tables I am using to fill a gridview. The tables have a common field named RangeActivityID. My problem is that the database is very old and some of the older entries do not match up IDs between tables, so I am unable to add an association between them in the database.
I do not care about the old data which doesn't match up, so in my .dbml file, I manually created an association in order to select good data from both tables. This is the LINQ query I have:
var collective = from p in rangeConnection.RangeActivities
orderby p.RangeActivityID
select new
{
TestName = p.TestName,
DateTime = p.ActivityDateTime,
Notes = p.Notes,
//RoundSerialNumber = p.RoundFire.RoundSerialNumber,
//RoundType = p.RoundFire.RoundType,
//LotStockNumber = p.RoundFire.LotNumber
};
I can set my grid datasource to 'collective' and everything works, but if I uncomment the three commented lines, the query returns no results because the tables have data that doesn't meet the association criteria. Is there a way to have the LINQ query ignore results that do not match up?
Thanks in advance!

Try to add where p.RoundFire != null criteria.

Suggest a join instead, and emulating a SQL LEFT JOIN.
var q = from p in rangeConnection.RangeActivities
join r in rangeConnection.RoundFires
on p.RangeActivityID equals r.RangeActivityID into sr
from x in sr.DefaultIfEmpty()
select new
{
TestName = p.TestName,
DateTime = p.ActivityDateTime,
Notes = p.Notes,
RoundSerialNumber = x.RoundSerialNumber,
RoundType = x.RoundType,
LotStockNumber = x.LotNumber
//consider checking for string.IsNullOrEmpty()
//for the RoundFires properties
};
The syntax for your entities may be inaccurate, but please edit my answer if it helps lead you to a solution.

Related

get column name in addition to the result (oracle)

I have a program in c# (asp.net environment) that dynamically runs ORACLE queries.
the queries can be like:
select * from app_costumers;
select a.first_name, a.last name, b.salary from app_costumers inner join app_costs b on a.id = b.id;
(As you can see, this is sometimes about a single table and sometimes more.
Sometimes writing the column names and sometimes using only in "*").
until now, I returned only the results,
But now I need to return the names of the results columns.
Do you have any idea how to do this?
(I can't use something like this:
SELECT column_name FROM user_tab_cols WHERE table_name = UPPER ('app_costumers');
Because it only fits for one table ...).
Thank you
You can use reader.GetName(i), for example:
var reader = cmd.ExecuteReader();
var columns = new List<string>();
for(int i=0;i<reader.FieldCount;i++)
{
columns.Add(reader.GetName(i));
}

Query with linq using a where clause

Okay so I've already asked this question but I've narrowed it down and am now able to word it better.
I have a sql database and an asp.net mvc project with entity frameworks. I already figured out how to query the database and display all contents. But now I need to query the database and only display the rows where column "a" is greater than or equal to column "b".
Edit: datatypes in both columns are int
Here is the query I need
Select *
from Inventory
Where quantity <= statusLow
var context = new MyContext();
var query = context.Inventory.Where(p=> p.quantity <= p.statusLow); // write the statement to query
var result = query.ToList(); // obtaining the result, trigger the database
You can try as shown below.
using (var db = new yourContext())
{
var result = db.Inventory.Where(a=> a.quantity <= a.statusLow).ToList();
}
You can learn more about LINQ to Entities here.

Pulling data from one SQL Azure table, add a column, then populate a different table

I using C# and LINQ to pull/push data housed in SQL Azure. The basic scenario is we have a Customer table that contains all customers (PK = CompanyID) and supporting tables like LaborTypes and Materials (FK CompanyID to Customer table).
When a new customer signs up, a new record is created in the Customers table. Once that is complete, I want to load a set of default materials and laborTypes from a separate table. It is simple enough if I just wanted to copy data direct from one table to another but in order to populate the existing tables for the new customer, I need to take the seed data (e.g. laborType, laborDescription), add the CompanyID for each row of seed data, then do the insert to the existing table.
What the best method to accomplish this using C# and LINQ with SQL Azure?
An example of a direct insert from user input for LaborTypes is below for contextual reference.
using (var context = GetContext(memCustomer))
{
var u = GetUserByUsername(context, memUser);
var l = (from lbr in context.LaborTypes
where lbr.LaborType1.ToLower() == laborType
&& lbr.Company == u.Company
select lbr).FirstOrDefault();
if (l == null)
{
l = new AccountDB.LaborType();
l.Company = u.Company;
l.Description = laborDescription;
l.LaborType1 = laborType;
l.FlatRate = flatRate;
l.HourlyRate = hourlyRate;
context.LaborTypes.InsertOnSubmit(l);
context.SubmitChanges();
}
result = true;
}
What you'll want to do is write a query retrieving data from table B and do an Insert Statement on Table A using the result(s).
This has been covered elsewhere in SO I think, here would be a good place to start
I don't know the syntax for Linq specifically; but by constructing something similar to #Murph 's answer beyond that link, I think this might work.
var fromB= from b in TableB
where ... ;//identify the row/data from table B
// you may need to make fromB populate from the DB here.
var toInsert = ...; //construct your object with the desired data
// do other necessary things here
TableA.InsertAllOnSubmit(toInsert);
dc.SubmitChanges(); // Submit your changes

Convert table name (in string) to use it in the LINQ query : C#, Entity Framework

I have a list of table names in form of strings. I want to loop through the list and use the table name in the LINQ query:
var db = new SomeContext();
// for a single table I can use the LINQ query as
var res = from q in db.Table
where ......
select q;
and it works just fine.
The above approach is hard coding. I need a generic solution for this to loop through multiple tables whose names are stored in a list.
// list of string containing table names
List<stringtableNames = [Get the table list from some source]
// not a problem here
loop through the table names and for each name execute a LINQ query as shown below
foreach(string table in tableNames)
{
var queryRes = from t in table
where <some_condition>
select t;
}
In the above statements "from t in table" above is not valid as "table" is a string. I need actual table object reference to use.
Need help on how do I go about doing that.
You can use the DbContext.Set method:
Set(System.Type.GetType("TableName"))
Above sentence will return a non generic DbSet. So, you will not be able to query with linq as usual. But you can use dynamic linq. ScottGu will explain it better than me.
Please, check this thread for other solutions.
In EF you can execute SQL Code.
In this example i use EF with SQL (String)
var db = new SomeContext();
var list = db.ExecuteStoreQuery<Obj>(Obj.sql);
class Obj
{
public const string sql = #"select [tbl].[field] from [tbl]";
}
select, where, from is one way to define LINQ but You can use it if you have a list of elements (IEnumerable<T> for example), but You have only name of Your table
I think You have to create a regular SQL query
foreach(string table in tableNames)
{
var query =$"select * from {table} where <some_condition>";
var list = db.ExecuteStoreQuery<Obj>(query);
}
In EF You can execute regular query

check if values are in datatable

I have an array or string:
private static string[] dataNames = new string[] {"value1", "value2".... };
I have table in my SQL database with a column of varchar type. I want to check which values from the array of string exists in that column.
I tried this:
public static void testProducts() {
string query = "select * from my table"
var dataTable = from row in dt.AsEnumerable()
where String.Equals(row.Field<string>("columnName"), dataNames[0], StringComparison.OrdinalIgnoreCase)
select new {
Name = row.Field<string> ("columnName")
};
foreach(var oneName in dataTable){
Console.WriteLine(oneName.Name);
}
}
that code is not the actual code, I am just trying to show you the important part
That code as you see check according to dataNames[index]
It works fine, but I have to run that code 56 times because the array has 56 elements and in each time I change the index
is there a faster way please?
the Comparison is case insensitive
First, you should not filter records in memory but in the datatabase.
But if you already have a DataTable and you need to find rows where one of it's fields is in your string[], you can use Linq-To-DataTable.
For example Enumerable.Contains:
var matchingRows = dt.AsEnumerable()
.Where(row => dataNames.Contains(row.Field<string>("columnName"), StringComparer.OrdinalIgnoreCase));
foreach(DataRow row in matchingRows)
Console.WriteLine(row.Field<string>("columnName"));
Here is a more efficient (but less readable) approach using Enumerable.Join:
var matchingRows = dt.AsEnumerable().Join(dataNames,
row => row.Field<string>("columnName"),
name => name,
(row, name) => row,
StringComparer.OrdinalIgnoreCase);
try to use contains should return all value that you need
var data = from row in dt.AsEnumerable()
where dataNames.Contains(row.Field<string>("columnName"))
select new
{
Name = row.Field<string>("columnName")
};
Passing a list of values is surprisingly difficult. Passing a table-valued parameter requires creating a T-SQL data type on the server. You can pass an XML document containing the parameters and decode that using SQL Server's convoluted XML syntax.
Below is a relatively simple alternative that works for up to a thousand values. The goal is to to build an in query:
select col1 from YourTable where col1 in ('val1', 'val2', ...)
In C#, you should probably use parameters:
select col1 from YourTable where col1 in (#par1, #par2, ...)
Which you can pass like:
var com = yourConnection.CreateCommand();
com.CommandText = #"select col1 from YourTable where col1 in (";
for (var i=0; i< dataNames.Length; i++)
{
var parName = string.Format("par{0}", i+1);
com.Parameters.AddWithValue(parName, dataNames[i]);
com.CommandText += parName;
if (i+1 != dataNames.Length)
com.CommandText += ", ";
}
com.CommandText += ");";
var existingValues = new List<string>();
using (var reader = com.ExecuteReader())
{
while (read.Read())
existingValues.Add(read["col1"]);
}
Given the complexity of this solution I'd go for Max' or Tim's answer. You could consider this answer if the table is very large and you can't copy it into memory.
Sorry I don't have a lot of relevant code here, but I did a similar thing quite some time ago, so I will try to explain.
Essentially I had a long list of item IDs that I needed to return to the client, which then told the server which ones it wanted loaded at any particular time. The original query passed the values as a comma separated set of strings (they were actually GUIDs). Problem was that once the number of entries hit 100, there was a noticeable lag to the user, once it got to 1000 possible entries, the query took a minute and a half, and when we went to 10,000, lets just say you could boil the kettle and drink your tea/coffee before it came back.
The answer was to stick the values to check directly into a temporary table, where one row of the table represented one value to check against. The temporary table was keyed against the user who performed the search, so this meant other users searches wouldn't become corrupted with each other, and when the user logged out, then we knew which values in the search table could be removed.
Depending on where this data comes from will depend on the best way for you to load the reference table. But once it is there, then your new query will look something like:-
SELECT Count(t.*), rt.dataName
FROM table t
RIGHT JOIN referenceTable rt ON tr.dataName = t.columnName
WHERE rt.userRef = #UserIdValue
GROUP BY tr.dataName
The RIGHT JOIN here should give you a value for each of your reference table values, including 0 if the value did not appear in your table. If you don't care which one don't appear, then changing it to an INNER JOIN will eliminate the zeros.
The WHERE clause is to ensure that your search only returns the unique items that you are looking for at the moment - the design should consider that concurrent access will someday occur here (even if it doesn't at the moment), so writing something in to protect it is advisable.

Categories

Resources