Delphi7, dbExpress and Master Detail relationship - delphi

I'm new to Delphi. I got two TSQLTables (say A and B) linked to two TClientDataSets (say cdsA and cdsB respectively) by two TDataSetProviders, two DataSources (dsA and dsB) complete the scenario.
Let A be the master one and let B be the detail one.
B.MasterSource is set to dsA value and B.MasterFields value refer to a field that does not exists in cdsA (but exists in the query). When I start the application I open cdsA first and then I open cdsB. Something goes wrong. The DBGrid that link to dsA datasource shows data, the DBGrid that link to dsB does not show anything. The SQLMonitor logfile shows that the query implemented in B is executed (a simple select a, b, c from tableB ). The stuff works fine if I change the query and show the field 'X' (select a, b, c, X from tableB) where 'X' is the field referred by B.IndexFieldNames property.
Why the DBGrid that link to dsB does not show the B's record related to cdsA's current record? Does it works only if I specify the IndexFieldNames in the query columns? What did I miss? TIA.

I'll explain the complete scenario using AdventureWorks database for SQL Server 2008 R2. I'll also assume that you've already placed the TSQLConnection component and properly set its parameters to established connection with your database. For this example, I'll also assume the name for it to be Conn1.
On a form, place 2 TSQLTable (named tableA and tableB), 2 TDataSetProvider (named dspA and dspB), 2 TClientDataSet (named cdsA and cdsB), 2 TDataSource (named dsA and dsB) and 2 TDBGrid (named gridA and gridB) components.
Set properties as follows:
tableA.SQLConnection = Conn1
tableA.SchemaName = Sales
tableA.TableName = Customer
tableA.Active = True
dspA.DataSet = tableA
cdsA.ProviderName = dspA
cdsA.Active = True
dsA.DataSet = cdsA
gridA.DataSource = dsA
tableB.SQLConnection = Conn1
tableB.SchemaName = Sales
tableB.TableName = SalesOrderHeader
tableB.Active = True
dspB.DataSet = tableB
cdsB.ProviderName = dspB
cdsB.MasterSource = cdsA
cdsB.MasterFields = CustomerID
cdsB.Active = True
dsB.DataSet = cdsB
gridB.DataSource = dsB
In gridA you should see all Customers, and in gridB you should see only Orders related to curently selected customer.
This is the basic example of establishing master/detail relationship between two TClientDataSet components in Delphi. However, there are other ways to do this.

The way that I link ClientDataSets is outlined in Cary Jensen's book "Delphi In Depth: Client DataSets". Setup the Master and Detail datasets as per normal, and ensure that they are linked via a TDataSource (you will have a parameter in the Detail SQL that links it to the Master). However, CJ suggests then having only one DataSetProvider which is attached to the Master. But the master (and therefore the DSP) will have a Nested DataSet reresenting the detail table. The detail / nested dataset can appear in the master table DBGrid or in its own DBGrid. Your gridB will get linked to the Nested Dataset.
The problem in linking gridB directly back to the TSQLQuery (as I understand) is that any updates to the master CDS are not reflected in gridB. If you want to see more then you can download the project NestedFromMasterDetail from Cary's web site.
If you really want to know more, then buy a copy of Cary's book. I have found it invaluable in understanding Client Data Sets. They are setup somewhat different and Cary does a good job of explaining their architecture.

Related

Delphi, Master-Detail with DetailFields in the where condition (not in select-part)

I am using master-detail connection to show a list of assigned columns of a detail-table. In addition i want to show a second grid with not assigned detail columns
Example
Master-Table t_human: idHU, nameHU (like John, Oscar, ...)
Detail-Table t_property: idPO, namePO (like male, female, blond hair, beard, blue eyes ...)
Join-Table t_hu_po: idHU, idPO
-> John - male, blond hair
-> Oscar - male, blue eyes, beard
When i select a master table row i want to show the assigned porperties and also the not assigned ones. The master-detail for the assigned properties works fine.
But for the not-assigned properties doesn't work.
Detail-SQL:
select p.idPO, p.namePO
from t_property p
where not exists (select * from t_hu_po hp where hp.idHU = :idHU and hp.idPO = p.idPO)
Master-SQL:
select idHU, nameHU from human
When i try to select the detailfield in the delphi component (Devart, SDAC, TMSQuery) it only shows me the fields for p.idPO and p.namePO. The :idHU parameter in the statement is configured as parameter for the query in the component. When i manually type the idHU in the DetailFields property of the Dataset (TMSQuery) i get an Invalid column name 'idHU'.. from delphi when activating the query.
Does someone knows a better solution than doing it with events for datachange and manually setting the detail-parameter and refreshing the detail-query.
My thought was, that master-detail would do the same thing but only in background, so that i don't have do code it.
Thanks
Stephan
Instead of using the where not exists try where p.idPO not in (Select idPO from t_hu_po where idHU=:idHu)
By makinge the subquery simply return all the idPOs that exist for the selected idHu, your query now looks for the properties that are not in that list.

Best Data Access approach for asp.net mvc application with big data

we have big challenge : Application is too slow because of huge records :(
we look for best data access pattern in web application (asp.net mvc 3)
with big data (sql server view with more than 66 million records.)
customers have forms with search fields and will see results within a grid of web page.
since now
we used both these data access ways:
1- entity framework with some features like compiled query
--get result
GridModelsResult = VwLoanInquiryList.Skip(pageIndex * pageSize).Take(pageSize).ToList();
--get count
int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);
2- sql server store procedure for pagination and get only current page results
--get result
select t1.* into #t from
(select *
FROM VwLoanInquiry
where CustomerNumber like '%'+#CustomerNumber+'%'
) AS [t1]
WHERE (#PageIndex=-1 or (t1.ID BETWEEN (#PageIndex-1)* #RecordPerPage AND ((#PageIndex)* #RecordPerPage)-1))
--get count
select count(*) from #t
3- OLAP; we made cube in analysis services (SSAS)
but here our problem is to show records with string column type within Cube Cells (its impossible to define Non-numeric fields for measures )
in additon ,
to get result faster,our view has index and data types of column has been set .
please help us to know which one of these ways are better ,or if there is an other way what is that?
thanks

SQL Server Full-Text search fails when searching more than one word

Symptoms:
Searching for a single word (i.e. "Snap") works
Searching for another word contained in the same field (i.e. "On") also works
Searching for "Snap On" at the same time returns 0 results, even though it shouldn't.
The setup:
SQL Server 2008 R2 with Advanced Features
nopCommerce 3.0
Things I have done:
I added the Product.MetaKeywords column to the full text search catalog
I added a bit into the Stored Procedure that performs the search to search through the MetaKeywords
Now the nopCommerce boards are fairly slow, but I'm positive the problem is within the SQL Stored Procedure anyway, so I figured I would ask for some SQL Server help here, even if you aren't familiar with the nopCommerce web app, you may have some information you can help me with.
The stored procedure in question is too large to post entirely here, but basically it dynamically adds "OR" or "AND" in between the keyword searches to generate the phrase used in a Contains clause. It selects through several unions various searchable fields by using Contains.
Here is the bit I added into the stored procedure
SET #sql = #sql + '
UNION
SELECT p.Id
FROM Product p with (NOLOCK)
WHERE '
IF #UseFullTextSearch = 1
SET #sql = #sql + 'CONTAINS(p.[MetaKeywords], #Keywords) '
ELSE
SET #sql = #sql + 'PATINDEX(#Keywords, p.[MetaKeywords]) > 0 '
#Keywords, at this point, if I am reading the procedure correctly, has a value of: "Snap* AND On*"
I don't understand why my query of "Snap On" returns 0 results, but "Snap" and "On" individually work fine.
The minimum search length is set to 1, so it's not that.
I should add that searching for "Snap* OR On*" works, but I cannot use OR because then searching for "Snap On" will also return "Snap Dragon" and other unrelated things.
--EDIT--
The problem wasn't any of that. I got some advice elsewhere and the problem was actually the stoplist. I managed to fix my issue simply by changing the stoplist on the product table from <system> to <off>.
To do this, follow these steps.
browse to your table in SQL Server management studio
Right click on the table and select "Full-Text Index"
Select "Properties" under "Full-Text Index"
In the "General" Tab, change "Full-Text Index Stoplist" to <off>
I had to do it this way because I was unable to get the transact SQL to work. It kept telling me there was no such object as the table I was attempting to modify. If anyone can provide any insight on how the Alter fulltext index statement works, I'm interested, because I was following the example on the MSDN page to the T and it just kept telling me there was no such object named Product.
The asterisk is not a plain old wildcard. If you are using it anywhere other than at the end of a search term, you're probably not using it correctly. See answers to a similar question
SQL Contains Question
In your case, each search term must be quoted separately. See this example from the docs http://technet.microsoft.com/en-us/library/ms187787(v=sql.90).aspx
SELECT Name
FROM Production.Product
WHERE CONTAINS(Name, '"chain*" OR "full*"');

How to use merge to insert value from a stored procedure

I am trying to do something like this:
merge MembershipTEST as T
using (select OrganisationID, Name From MembershipPending) as S
on T.OrganisationID = S.OrganisationID
and T.Name = S.Name
when not matched then
insert (MembershipID,OrganisationID, Name)
values(
(EXEC [dbo].[spGetNextIntKeyByTableName]
#PKColName = 'MembershipID',#TableName = 'FWBMembership'),
S.OrganisationID,
S.Name );
Bascially the identitykey is from a sp
Is it possible?
Update 1: Answer is NO
read the online doc http://msdn.microsoft.com/en-us/library/bb510625%28v=sql.105%29.aspx
VALUES ( values_list) Is a comma-separated list of constants,
variables, or expressions that return values to insert into the target
table. Expressions cannot contain an EXECUTE statement.
Build an SSIS package. Just create a new Data Flow task. Use two OLEDB sources make one of them execute the stored procedure and the other one select from the table you are looking to MERGE with. Make sure they are both ordered by the same thing. Go into advanced settings for each OLEDB source and set is sorted to true and then set the sort values for the items you are ORDERing BY. Then move both data flows to to a MERGE JOIN. Then send the Data flow to a Conditional Split and set as INSULL(OrganisationID). Use the resulting data flow to go to an OLEDB destination.
Sorry for the lack of visuals I will add them later when I'm on lunch hour to busy to add them now.

Silverlight / Data Challenging Issue

I'm a little stumped on this one. Anyone have any ideas? I'll try to lay out the example as brief as possible.
Creating Silverlight 3.0 application against SQL 2005 database. Using RIA Services and Entity Framework for data access.
I need to be able to populate a grid against a table. However, my grid UI and my table structure is different. Basically my grid needs to turn rows into columns (like a PIVOT table). Here are my challenges / assumptions
I have no idea until runtime which columns I will have on the grid.
Silverlight 3 only supports binding to properties
Silverlight 3 does not allow you to add a row to the grid and manually populate data.
As we all know, Silverlight does not have the System.Data (mainly DataTable) namespace
So, how do I create an object w/ dynamic properties so that I can bind to the grid. Every idea I've had (multi-dimensional arrays, hash tables, etc.) fall apart b/c SL needs a property to bind to, I can't manually add/fill a data row, and I can't figure out a way to add dynamic properties. I've seen an article on a solution involving a linked list but I'm looking for a better alternative. It may come down to making a special "Cody Grid" which will be a bunch of text boxes/labels. Doable for sure but I'll lose some grid functionality that users expect
The ONLY solution I have been able to come up is to create a PIVOT table query in SQL 2005 and use an entity based on that query/view. SQL 2008 would help me with that. I would prefer to do it in Silverlight but if that is the last resort, so be it. If I go the PIVOT route, how do I implement a changing data structure in Entity Framework?
Data Sample.
Table
Name Date Value
Cody 1/1/09 15
Cody 1/2/09 18
Mike 1/1/09 20
Mike 1/8/09 77
Grid UI should look like
Name 1/1/09 1/2/09 1/3/09 .... 1/8/09
Cody 15 18 NULL NULL
Mike 20 NULL NULL 77
Cody
My team came up with a good solution. I'm not sure who deserves the credit but it's somewhere in google land. So far it works pretty good.
Essentially the solution comes down to using reflection to build a dynamic object based on this dynamic data. The function takes in a 2-dimensional array and turns it into a List
object with properties that can be bound. We put this process in a WCF Service and it seems to do exactly what we need so far.
Here is some of the code that builds the object using Reflection
AppDomain myDomain = AppDomain.CurrentDomain;
AssemblyName myAsmName = new AssemblyName("MyAssembly");
AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name);
TypeBuilder myType = myModule.DefineType("DataSource", TypeAttributes.Public);
string columnName = "whatever";
for (int j = 0; j <= array.GetUpperBound(1); j++)
{
Type properyType = typeof(T);
FieldBuilder exField = myType.DefineField("_" + "columnName" + counter, properyType, FieldAttributes.Private);
//The following line is where I’m passing columnName + counter and getting errors with some strings but not others.
PropertyBuilder exProperty = myType.DefineProperty(columnName + counter.ToString(), PropertyAttributes.None, properyType, Type.EmptyTypes);
//Get
MethodBuilder exGetMethod = myType.DefineMethod("get_" + "columnName" + counter, MethodAttributes.Public, properyType, Type.EmptyTypes); ILGenerator getIlgen = exGetMethod.GetILGenerator();
//IL for a simple getter:
//ldarg.0
//ldfld int32 SilverlightClassLibrary1.Class1::_Age
//ret
getIlgen.Emit(OpCodes.Ldarg_0);
getIlgen.Emit(OpCodes.Ldfld, exField);
getIlgen.Emit(OpCodes.Ret);
exProperty.SetGetMethod(exGetMethod);
//Set
MethodBuilder exSetMethod = myType.DefineMethod("set_" + "columnName" + counter, MethodAttributes.Public, null, new Type[] { properyType }); ILGenerator setIlgen = exSetMethod.GetILGenerator();
//IL for a simple setter:
//ldarg.0
//ldarg.1
//stfld int32 SilverlightClassLibrary1.Class1::_Age
//ret
setIlgen.Emit(OpCodes.Ldarg_0);
setIlgen.Emit(OpCodes.Ldarg_1);
setIlgen.Emit(OpCodes.Stfld, exField); setIlgen.Emit(OpCodes.Ret);
exProperty.SetSetMethod(exSetMethod);
counter++;
}
finished = myType.CreateType();
You can dynamically set columns with their associated bindings (ensuring that AutoGenerateColumns is off):
For instance, the name column:
DataGridTextColumn txtColumn = new DataGridTextColumn();
textColumn.Header = "Name";
textColumn.Binding = new Binding("FirstName");
myDataGrid.Columns.Add(txttColumn);
The ObservableCollection you use to store the data that is queried could possibly be overriden to support pivoting, making sure to change the binding of the DataGrid columns, as shown above.
Note: This is a fair amount of hand waving i'm sure (haven't touched silverlight for over a year); but I hope it's enough to formulate another strategy.
if you are working with two dimensional array then adding columns dynamically as shown above will not work.
The problem is with silverlight it cannot understand the binding of columns to a list.
So we have to create list of rows with row convertor that will represent our two dimensional arrays.
this one worked for me
http://www.scottlogic.co.uk/blog/colin/2010/03/binding-a-silverlight-3-datagrid-to-dynamic-data-via-idictionary-updated/

Resources