Querying 2 datatables in a dataset - c#

I have 2 datatables named 'dst' and 'dst2'. they are located in the dataset 'urenmat'.
The mayority of the data is in 'dst'. this however contains a column named 'werknemer'. It contains a value which corresponds to a certain row in 'dst2'. This column is named 'nummer'.
What i need is a way to left outer join both datatables where dst.werknemer and dst2.nummer are linked, and a new datatable is created which contains 'dst2.naam' linked to 'dst.werknemer' along with all the other columns from 'dst'.
I have looked everywhere and still can't seem te find the right answer to my question. several sites provide a way using LINQ in this situation. I have tried using LINQ but i am not so skilled at this.
I tried using the 101 LINQ Samples:
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
urenmat = dataset.
dst = a, b, c, d, werknemer.
dst2 = nummer, naam.
I used the following code from '101'.
var query =
from contact in dst.AsEnumerable()
join order in dst2.AsEnumerable()
on contact.Field<string>("werknemer") equals
order.Field<string>("nummer")
select new
{
a = order.Field<string>("a"),
b = order.Field<string>("b"),
c = order.Field<string>("c"),
d = order.Field<string>("d"),
naam = contact.Field<decimal>("naam")};
I however don't know what to change 'contact' and 'order' to and i can't seem to find out how to save it to a datatable again.
I am very sorry if these are stupid questions but i have tried to solve it myself but it appears i'm stupid:P. Thank for the help in advance!
PS. i am using C# to code, the dataset and datatables are typed.

if you want to produce a projected dataset of dst left outer joined to dst2 you can use this LINQ expression (sorry i don't really work in LINQ query syntax so you'll have to use this lambda syntax instead).
var query = dst.AsEnumerable()
.GroupJoin(dst2.AsEnumerable(), x => x.Field<string>("werknemer"), x => x.Field<string>("nummer"), (contact, orders) => new { contact, orders })
.SelectMany(x => x.orders.DefaultIfEmpty(), (x, order) => new
{
a = order.Field<string>("a"),
b = order.Field<string>("b"),
c = order.Field<string>("c"),
d = order.Field<string>("d"),
naam = x.contact.Field<decimal>("naam")
});
because this is a projected dataset you cannot simply save back to the datatable. If saving is desired then you would want to load the affected row, update the desired fields, then save the changes.
// untyped
var row = dst.Rows.Find(keyValue);
// typed
var row = dst.FindBy...(keyValue);
// update the field
row.SetField("a", "some value");
// save only this row's changes
row.AcceptChanges();
// or after all changes to the table have been made, save the table
dst.AcceptChanges();
Normally if you need to perform loading and saving of (projected) data, an ORM (like entity framework, or LINQ-to-SQL) would be the best tool. However, you are using DataTable's in this case and I'm not sure if you can link an ORM to these (though it seems like it would probably be possible).

Related

How Create linq query select dynamic custom fileds

I want to reformat the data without going back to the database and in a dynamic way
So that the user can specify what columns he wants to collect
how I can
Write an sql string and execute it like EXECUTE IMMEDIAT in Oracle
Inside C# Linq
want to do a lock like combining two or more fields (multiply - merge...)
ToTable
It only allows me to specify the names of existing fields
FillDataSorce(params P)
{
// p It is a variable containing the field to be queried
//Like
//field1 = d["field1"] ,
//field2 = d["field2"] ,
//field sum = d["field1"] +d["field2"]
BSo.DataSource = from d in dt.AsEnumerable()
select new
{
P.Select(p => p) //col3col2 = d["col1"] + d["col2"] Dynamic field example
};
}

How to join tables using include with entity SQL

I will try to describe my issue in details.I have the following scenario.
1.) I have 3 tables : business, customoffice(Custom Office) and cusdesc(custom office description)
The relationship is that a business has on customoffice and one customoffice has many cusdesc.
The table business has a field customofficeno which is a foreign key to the field cuscode of the customoffice table.The table cusdesc has a field cuscode which is a foreign key to the field cuscode of the customoffice table.
The objective is to select a business including the custom office and custom office description using entity framework.
2.) Code
I have a procedure FillData which fills a datagrid. My objective is to display fields from the 3 tables. I managed to display data from tables "Business" and "Customoffice" but i need to display the description of a custom office via table "cusdesc" and be more specific the field "CSNAME".
3.) My issue is that when I include the ("CUSTOMSOFFICE.CUSDESC") the results do not contain data from table "CUSDESC" but only how many records much the criteria so I cannot access the field "CSNAME"
Hereafter is the procedure:
using (var _context = new ReftabEntities())
{
try
{
SetGlobalValues();
ObjectQuery<BUSINESS> q_business = _context.BUSINESS.Where("it.BUSINESSNO=" + int.Parse(pv_businessno)).Where(string.Format("(it.BUSINESSSTART <= DATETIME'{0:yyyy-MM-dd HH:mm}') and (it.BUSINESSCLOSED >= DATETIME'{0:yyyy-MM-dd HH:mm}')", pv_date)).Include("CUSTOMSOFFICE").Include("CUSTOMSOFFICE.CUSDESC");
gvBusinessList.Caption = "Total records selected: " + q_business.Count();
gvBusinessList.DataSource = q_business;
gvBusinessList.DataBind();
}
catch (Exception e)
{
errorPopup.Text = e.Message;
errorPopup.ShowOnPageLoad = true;
}
finally
{
_context.Dispose();
}
}
}
Can you please give a hint what I do wrong.
Thanks in advance.
The Include operator just asks EF to load a related entity with the query. If you don't use "Include", EF will only extract the properties of BUSINESS and will not extract the properties of the CUSTOMSOFFICE. There is no need for the "Include("CONSOMSOFFICE.CUSDESC")" since you already loaded the entire CUSTOMSOFFICE entity in the first Include.
I see that you're binding the result to the grid view, and if I understand correctly, the issue is that the "CUSTOMSOFFICE.CUSDESC" is not being displayed in the gridview. I believe this is because the gridview tries to render its representation of the "CUSTOMSOFFICE" object itself, since that's the direct property of the items you are binding. To have more control over the "columns" of your gridview, I suggest using LINQ to transform the results of your query into what you explicitly want to display.
I am assuming that BUSINESSNO, BUSINESSSTART, and BUSINESSCLOSED are properties of your Business entity itself, and that BUSINESSNO is the Primary Key. Let me rewrite your query into this:
var q_business = _context.BUSINESS.Include(b=>b.CUSTOMSOFFICE)
.Where(p => p.BUSINESSNO == int.Parse(pv_businessno)
&& p.BUSINESSSTART <= DateTime.Parse(pv_date)
&& p.BUSINESSCLOSED >= DateTime.Parse(pv_date) )
.FirstOrDefault();
This query would extract the details of the Business (including the related CUSTOMSOFFICE details) that matches the given pv_businessno and falls within your date criteria. But you can't bind this to your gridview yet because you might encounter the same problem where the CUSTOMSOFFICE.DESC is not displayed. To ensure proper display, you must identify what properties you want to include. For example, if you only want to display the set of properties below:
BUSINESS.BUSINESSNO
BUSINESS.BUSINESSNAME
BUSINESS.CUSTOMSOFFICE.CUSCODE
BUSINESS.CUSTOMSOFFICE.CUSDESC
You should transform your output to explicitly and immediately include these properties.
var q_business = _context.BUSINESS.Include(b=>b.CUSTOMSOFFICE)
.Where(b => b.BUSINESSNO == int.Parse(pv_businessno)
&& b.BUSINESSSTART <= DateTime.Parse(pv_date)
&& b.BUSINESSCLOSED >= DateTime.Parse(pv_date) )
.Select(b => new {BusinessNo = b.BUSINESSNO,
BusinessName = b.BUSINESSNAME,
CustomsOfficeCode = b.CUSTOMSOFFICE.CUSCODE,
CustomsOfficeDesc = b.CUSTOMSOFFICE.CUSDESC } ) //This Select statement creates a new anonymous type that has Businessno, BusinessName, CustomsOfficeCode, and CustomsOfficeDesc properties
.FirstOrDefault();
When you bind this to your gridview, it should be able to display the value of the CUSDESC property.

Linq-to-SQL select many columns

I'm using Linq-to-SQL and I just started to learn some of the basics. I have problem with select command many columns in many tables. I give songs which selected into session (contain songid) and display songname, artistname, genrename in datagrid.
But it's not working.
ArrayList SelectedSongs = (ArrayList)Session["SelectedSongs"];
string songIds = "";
foreach (int id in SelectedSongs)
songIds += id + ", ";
var query = from s in sa.Songs
from ar in sa.Artists
from g in sa.Genres
where s.SongID in (songIds)
select new { s.SongID, s.SongName, ar.ArtistName, g.GenreName };
dgSongs.DataSource = query;
Can anyone help me solve this problem.
Thanks.
This syntax is not correct Linq:
where s.SongID in (songIds)
The Linq equivalent of SQL's WHERE IN is to use Contains(). You have to turn the statement around and start with the list:
where songIds.Contains(s.SongID)
When using Linq-to-SQL you should always use navigation properties instead of explicit joins. If you have proper foreign keys between your tables those properties will be automatically created. With navigation properties and songIDs changed into an int[] your query should be something like this:
int[] songIDs = ((ArrayList)Session["SelectedSongs"]).OfType<int>().ToArray();
var query = from s in sa.Songs
where songIDs.Contains(s.SongID)
select new
{
s.SongID,
s.SongName,
s.Artist.ArtistName,
s.Genre.GenreName
};
Seems like you're trying to Join multiple tables. I would recommend to take a look at the Join section of this page. Good luck!
I believe you want songIds to be an int[] instead of a csv of ids.

Error from use of C# Linq SQL CONCAT

I have the following three tables, and need to bring in information from two dissimilar tables.
Table baTable has fields OrderNumber and Position.
Table accessTable has fields OrderNumber and ProcessSequence (among others)
Table historyTable has fields OrderNumber and Time (among others).
.
var progress = from ba in baTable
from ac in accessTable
where ac.OrderNumber == ba.OrderNumber
select new {
Position = ba.Position.ToString(),
Time = "",
Seq = ac.ProcessSequence.ToString()
};
progress = progress.Concat(from ba in baTable
from hs in historyTable
where hs.OrderNumber == ba.OrderNumber
select new {
Position = ba.Position.ToString(),
Time = String.Format("{0:hh:mm:ss}", hs.Time),
Seq = ""
});
int searchRecs = progress.Count();
The query compiles successfully, but when the SQL executes during the call to Count(), I get an error
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
Clearly the two lists each have three items, one of which is a constant. Other help boards suggested that the Visual Studio 2010 C# compiler was optimizing out the constants, and I have experimented with alternatives to the constants.
The most surprising thing is that, if the Time= entry within the select new {...} is commented out in both of the sub-queries, no error occurs when the SQL executes.
I actually think the problem is that Sql won't recognize your String.Format(..) method.
Change your second query to:
progress = progress.Concat(from ba in baTable
from hs in historyTable
where hs.OrderNumber == ba.OrderNumber
select new {
Position = ba.Position.ToString(),
Time = hs.Time.ToString(),
Seq = ""
});
After that you could always loop trough the progress and format the Time to your needs.

Convert DataTable to LINQ: Unable to query multiple fields

Importing a spreadsheet I have filled a DataTable object with that data and returns expected results.
Attempting to put this into a format I can easily query to search for problem records I have done the following
public void Something(DataTable dt)
{
var data = from row in dt.AsEnumerable()
select row["Order"].ToString();
}
Works as expected giving me a list of orders. However I cannot add other fields to this EnumerableRowCollection. Attempting to add other fields as follows gives me an error
public void Something(DataTable dt)
{
// row["Version"] throws an error on me
var data = from row in dt.AsEnumerable()
select row["Order"].ToString(), row["Version"].ToString();
}
Error: "A local variable named 'row' cannot be declared in this scope because it would give a different meaning to 'row' which is already used in a 'child' scope to donate something else"
I'm thinking I need to alias the column name but I'm having no luck. What am I missing here?
It sounds like you're writing a bad select statement. Try the following:
public void Something(DataTable dt)
{
var data = from row in dt.AsEnumerable()
select new {
Order = row["Order"].ToString(),
Something = row["Something"].ToString(),
Customer = row["Customer"].ToString(),
Address = row["Address"].ToString()
};
}
That will create a new collection of Anonymously Typed objects that you can iterate over and use as needed. Keep in mind, though, that you want be able to return data from the function. If you need that functionality, you need to create a concrete type to use (in place of anonymous types).
I think you should use select new like this query for example:
var q = from o in db.Orders
where o.Products.ProductName.StartsWith("Asset") &&
o.PaymentApproved == true
select new { name = o.Contacts.FirstName + " " +
o.Contacts.LastName,
product = o.Products.ProductName,
version = o.Products.Version +
(o.Products.SubVersion * 0.1)
};
You probably want the following.
var data = from row
in dt.AsEnumerable()
select new { Order = row["Order"].ToString(), Version = row["Version"].ToString() };

Categories

Resources