I have coded three select statements in stored procedure in Microsoft SQL Server 2005. Both select statements return multiple number of records and table list for select statements is different. One select records from a master table and the other from a child table. In C# code I want to get all these records and put all the data in one object. I am using SqlDataReader. Is it possible with it or should i do something else.
You use the NextResult method on the datareader to navigate with multiple results from a query.
To loop through all data you would do something like this:
var moreResults = true;
while (moreResults)
{
while (reader.Read())
{
...
}
moreResults = reader.NextResult();
}
So with that as a background, and assuming the master resultset comes first, populating master and detail objects could be done like this:
First, build up a dictionary of the Master records:
var masters = new Dictionary<int, Master>();
var idOrdinal = reader.GetOrdinal("id");
while (reader.Read())
{
var id = reader.GetInt32(idOrdinal);
masters.Add(id, new Master{Id=id, ....});
}
Next, move on to detail records and add those to their corresponding master:
reader.NextResult();
var masterIdOrdinal = reader.GetOrdinal("masterId");
while (reader.Read())
{
var masterId = reader.GetInt32(masterIdOrdinal);
var master = masters[masterId];
master.Details.Add(new Detail{....});
}
You should obviously replace column names with what you have in your data as well as supply the full initialization of Master and Detail objects.
If the detail resultset is sorted on master id, the last loop could be optimized to only lookup each master once from the dictionary. If the resultsets are small though, the gain would not be that huge.
...one select records from master table
and other from child table .in c# code
i want to get all this record and put
all this data in one object...
Peter's solution works to solve the basic problem of retrieving multiple results with a single DataReader. However, If you want to save your data to an object which replicates the relationship between the Master-Details tables, you should be using a DataSet instead.
DataSets can contain multiple DataTables and provide full support for inherent relationships between the tables by allowing creation of DataRelations between the tables. Then you can get related records for each scenario by calling GetChildRows() or GetParentRows() from the Master or Details tables respectively.
There are probably many samples online that illustrate how to do this. Here's one discussion thread from my Group where I have listed the steps and provided some code to demonstrate the procedure.
Related
I need data for a LINQ query that is not already saved to the database. Here is my code:
foreach (var item in BusProc)
{
var WorkEffortTypeXref = new WorkEffortTypeXref
{
SourceDataEntityTypeName = "BusProc",
SourceDataEntityTypeId = item.BusProcId,
};
_clDBContext.WorkEffortTypeXref.AddRange(WorkEffortTypeXref);
}
but I need this data in the SQL Database before I do a join LINQ query on the data. Although I don't really want to do a OnSave() after this function because I want to make the whole process transactional.
This is the LINQ I need to execute. What is the best way to do this?
var linqquery = from bupr in BusProc
join wrtx in WorkEffortTypeXref on bupr.BusProcId equals wrtx.SourceDataEntityTypeId
// where wrtx.SourceDataEntityTypeName == "BusProc"
select new
{
wrtx.TargetDataEntityTypeId
};
First, try to compile your code. This code won't compile and as-is isn't comprehensible. You are treating WorkEffortTypeXref as a class, a singular object and a list all in the first section of code, so we really can't know what it is supposed to be.
Now, as I understand your question, you want to query information that is being added to a table, (currently stored in memory as a collection of some sort) but you want to query it before it is added? What if the table has other rows that match your query? What if the insert violates a constraint and therefore fails? Linq can query an in-memory collection, but you have to choose, are you querying the collection that you have in memory (and isn't yet a row of your table) or the database (which has all of the rules/contstraints/etc that databases provide)? Until the records are saved to your table, they aren't the same thing.
I have 2 database with tables.
I wanted to insert records from first database to second database table in LINQ. I have created 2 dbml files with 2 datacontexts but I am unable to code the insertion of records.
I have list of records:
using(_TimeClockDataContext)
{
var Query = (from EditTime in _TimeClockDataContext.tblEditTimes
orderby EditTime.ScanDate ascending
select new EditTimeBO
{
EditTimeID = EditTime.EditTimeID,
UserID = Convert.ToInt64(EditTime.UserID),
ScanCardId = Convert.ToInt64(EditTime.ScanCardId),
}).ToList();
return Query;
}
Now I want to insert record in new table which is in _Premire2DataContext.
If you want to "copy" records from one database to another using Linq then you need two database contexts, one for the database you are reading from, and one for the database you are reading to.
EditTime[] sourceRows;
using (var sourceContext = CreateSourceContext())
{
sourceRows = ReadRows(sourceContext);
}
using (var destinationContext = CreateDestinationContext())
{
WriteRows(destinationContext, sourceRows);
}
You now just need to fill in the implementations for ReadRows and WriteRows using standard LINQ to SQL code. The code for writing rows should look a bit like this.
void WriteRows(TimeClockDataContext context, EditTime[] rows)
{
foreach (var row in rows)
{
destinationContext.tblEditTimes.Add(row);
}
destinationContext.SubmitChanges();
}
Note that as long as the schema is the same you can use the same context and therefore the same objects - so when reading records we ideally want to return the correct array type, therefore reading is going to look a bit like this
EditTime[] ReadRows(TimeClockDataContext context)
{
return (
from EditTime in _TimeClockDataContext.tblEditTimes
orderby EditTime.ScanDate ascending
select EditTime
).ToArray();
}
You can use an array or a list - it doesn't really matter. I've used an array mostly because the syntax is shorter. Note that we return the original EditTime objects rather than create new ones as this means we can add those objects directly to the second data context.
I've not compiled any of this code yet, so it might contain some typos. Also apologies if I've made some obvious errors - its been a while since I last used LINQ to SQL.
If you have foreign keys or the second database has a different schema then things get more complicated, but the fundamental process remains the same - read from one context (using standard LINQ to SQL) and store the results somewhere, then add the rows the the second context (using standard LINQ to SQL).
Also note that this isn't necessarily going to be particularly quick. If performance is an issue then you should look into using bulk inserts in the WriteRows method, or potentially even use linked servers to do the entire thing in SQL.
To me, PetaPoco's Database.Fetch and Database.Query seem to be doing the same thing.
For example,
var db = new PetaPoco.Database("myDB");
ProductList products = db.Fetch<ProductList>("SELECT * FROM ProductList");
ProductList products = db.Query<ProductList>("SELECT * FROM ProductList");
Is there any significant difference between them?
According to the PetaPoco documentation, this is the answer:
Query vs Fetch
The Database class has two methods for retrieving records Query and Fetch. These are pretty much identical except Fetch returns a List<> of POCO's whereas Query uses yield return to iterate over the results without loading the whole set into memory.
Fetch and query behave differently if you use them inside a transaction. I had a use case where I needed to update several tables in one transaction but I needed to retrieve some data from a reference table in the middle of the sequence.
When I retrieved the data with Query, and subsequent Inserts or Updates failed with an InvalidOperationException: "There is already an open DataReader associated with this Command which must be closed first"
The solution was to replace the Query with a Fetch and I was able to complete the sequence.
The pseudocode for this is:
BeginTransaction
Update Tbl1
Update Tbl2
Query RefTblA ## Changed Query to Fetch to avoid: '...already an open DataReader..." exception
Update Tbl3 using data from RefTblA
CompleteTransaction
I have two tables. One in one database and one in a separate database. I need to populate a dropdown list with options from the first, filtered by the second. I am using Linq-to-SQL. Below is how I pull the "un-filtered" list.
public static DataTable GetSPCCodeList()
{
using (var context = ProviderDataContext.Create())
{
IQueryable<tblProviderAdminSPCCode> tSPCCode = context.GetTable<tblProviderAdminSPCCode>();
return (tSPCCode
.Where(spcCode => spcCode.Inactive == null)
.OrderBy(spcCode => spcCode.SPCCodeID)
.Select(spcCode => new
{ spcCode.SPCCodeID, spcCode.SPCDescription,
spcCode.SPCCategoryID }))
.CopyLinqToDataTable();
}
}
The table I need to filter against simply contains a column for SPCCodeID. How would I go about filtering my List based on if they exist in the second table?
Generate and execute a LINQ query on the other database to get a collection of your SPCCodeIDs into memory variable e.g.
IList<int> spcCodeIDs = /* query goes here */;
Then run your query but replace the Where clause like this
.Where(spcCode => spcCode.Inactive == null
&& spcCodeIDs.Contains(spcCode.SPCCodeID))
I would create a list of these SPCCodeID values from the other database and then modify your where clause to be:
.Where(spcCode => spcCode.Inactive == null && spcCodeList.Contains(spcCode.SPCCodeID))
Remember to make the scpCodeList an actual List using ToList() because I think it will have issues if you make a query with two different DataContexts.
You can actually make LINQ to SQL select from multiple SQL databases at the same time if they are on the same server and available on a single connection string.
There are two options:
Create a view in the first database that links to the second
Create temporary data context, copy the DBML details out and modify the table name
Full details on how to do these are actually listed on my blog rather than repeating them here: http://damieng.com/blog/2010/01/11/linq-to-sql-tips-and-tricks-3
Using a SubSonic (2.2) SqlQuery object, I am querying a view that contains distinct rows from another table. The results of the query, however, contain multiple rows for certain rows in the view. It appears to be because of a join on a temporary table in the query generated to achieve paging. How can I avoid this duplication of rows?
Bonus points: I have to use the view because SubSonic can't do .Paged() and .Distinct() at the same time. Why not?
If I remember correctly you have to use distinct on the right position.
var query = DB.Select().From<Products>()
.Where(Products.CategoryColumn).IsEqualTo(5).Distinct();
var query = DB.Select().Distinct().From<Products>()
.Where(Products.CategoryColumn).IsEqualTo(5);
Both statements compile but the first generates invalid sql code. A good starting point for debugging SubSonic SqlQueries is to generate the output:
var sql = query.BuildSqlStatement();
Another solution could be to use Group instead of distinct so you can avoid the view in the first place.