What's difference between "t1.__index = t2" and "setmetatable(t1, {__index = t2})"? - oop

I seen this things in others code, and if I understood correctly it should be used like this:
t1 = {}
t1.__index = t2 --1
function t1:new()
local new = {}
setmetatable(new, {__index = t1}) --2
new.something = 0
return new
end
But what they really do and why have different way of writing?

They are written differently because they do different things.
t1 = {}
t2 = {a = 20}
meta = {__index = t2}
setmetatable(t1, meta)
print(t1.a) -- prints 20
Note how there's 3 tables here: meta, the metatable, t2, which stores the key a and t1 which we want to set to look up missing keys in t2.
The metatable only serves teh purpose of controlling the behavior of t1, but, to use less tables, people often use the fallback table (t2) as the metatable (meta) so it becomes something like
t1 = {}
t2_and_meta = {a = 20}
t2_and_meta.__index = t2_and_meta
setmetatable(t1, t2_and_meta)
print(t1.a) -- prints 20

Related

Easiest way of defining and using of Global Variable

"first part" &&&& fun _ ->
let ident
"second part" &&&& fun _ ->
ident ....
I need to use variable "ident".
I just need to pass value of variable from first part of test to second one...
I want to ask you if there is any easy way how to define and use global variable or even if you have better (and easy) idea of doing that
Keep in mind, please, that I am a beginner, so I would prefer easier ones.
Global variables will often make your code difficult to work with - particularly if they are mutable.
Instead, consider returning the values you need to keep track of as composite values. An easy data type to start with would be a tuple:
let ``first part`` id =
let someOtherValue = "Foo"
someOtherValue, id + 1
This function takes an int (the current ID) as input, and returns string * int (a tuple where the first element is a string, and the second element and int) as output.
You can call it like this:
> let other, newId = ``first part`` 42;;
val other : string = "Foo"
val newId : int = 43
Notice that you can use pattern matching to immediately destructure the values into two named symbols: other and newId.
Your second function could also take an ID as input:
let ``second part`` id otherArgument =
// use id here, if you need it
"Bar"
You can call it like this, with the newId value from above:
> let result = ``second part`` newId "Baz";;
val result : string = "Bar"
If you find yourself doing this a lot, you can define a record for the purpose:
type Identifiable<'a> = { Id : int; Value : 'a }
Now you can begin to define higher-order functions to deal with such a type, such as e.g. a map function:
module Identifiable =
let map f x = { Id = x.Id; Value = f x.Value }
// Other functions go here...
This is a function that maps the Value of an Identifiable from one value to another, but preserves the identity.
Here's a simple example of using it:
> let original = { Id = 42; Value = "1337" };;
val original : Identifiable<string> = {Id = 42;
Value = "1337";}
> let result' = original |> Identifiable.map System.Int32.Parse;;
val result' : Identifiable<int> = {Id = 42;
Value = 1337;}
As you can see, it preserves the value 42, but changes the Value from a string to an int.
You can still change the ID explicitly, if you want to do that:
> let result'' = { result' with Id = 7 };;
val result'' : Identifiable<int> = {Id = 7;
Value = 1337;}
Since this was getting out of hand for comments this is how I would do it for an example
let mutable t = 0
let first =
t <- 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2
In some cases you have to use a ref:
let t = ref 0
let first =
t := 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2 -
// you use "!t" to get the value
If you define ident at the top of your file like this :
let ident = "foo"
// rest of your code using ident
ident are global and you can use in the next part of your file.
EDIT :
If ident wil change in the next part of your code, use this :
let ident = ref "foo"

the multi part identifier could not be bound in an update query

First of all I've looked at similar questions but failed to find one for my case.
The access code i am turning into sql is as follows (I didn't write it)
UPDATE QUpdateTrialstepApproved1
INNER JOIN TrialStepApproved ON
QUpdateTrialstepApproved1.cid_req = TrialStepApproved.cID
SET TrialStepApproved.wm21 = [wm2_req],
TrialStepApproved.sw = [startweek_req],
TrialStepApproved.PlannedTotalm2 = [m2_req],
TrialStepApproved.ew = [endweek_req],
TrialStepApproved.ActualNrofDiffEntries = [entries_req],
TrialStepApproved.entryfactorTrial1 = [eFtrial_req],
TrialStepApproved.fixeddeliveryweek = [fixedEndweek_req],
TrialStepApproved.culturename = [culturename_req]
WHERE (((QUpdateTrialstepApproved1.approveRequestChange)="v")
AND ((TrialStepApproved.Location) Is Not Null));
I've turned it into the following but I get the error in the title:
UPDATE A
SET B.wm21 = [wm2_req],
B.sw = [startweek_req],
B.PlannedTotalm2 = [m2_req],
B.ew = [endweek_req],
B.ActualNrofDiffEntries = [entries_req],
B.entryfactorTrial1 = [eFtrial_req],
B.fixeddeliveryweek = [fixedEndweek_req],
B.culturename = [culturename_req]
from QUpdateTrialstepApproved1 as A
INNER JOIN TrialStepApproved as B ON A.cid_req = B.cID
WHERE A.approveRequestChange='v' AND B.Location Is Not Null
You're updating B, not A. Change the first line to
UPDATE B
...and thing will work fine.
An SQLfiddle.

SQL performance linq indexes

I have a SQL database where i store routes. I store routeinformation in one table and the coordinates in another table.
Right now i have around 40 routes with 50k coordinates if you sum all routes.
I use the following LINQ code to get the data
var query = (from b in db.routes select new {
name = b.name,
id = b.route_id,
coor = b.coordinates.Select(c => new
{
seq = c.sequence,
lat = c.position.Latitude,
lon = c.position.Longitude
}) });
This query takes 4.5sec to execute, i find that to be kind.
I'm new to indexes, right now both primary-keys are clustered indexes, and primary keys are normal(??)-indexes that i created with the following SQL-command:
CREATE INDEX IX_route on [db].[coordinates] (route_id)
Is my database slow or is this normal for this amount of data?
If you can deal with your results flattened, this query might give you better performance:
var query = from b in db.routes
from c in b.coordinates
select new
{
name = b.name,
id = b.route_id,
coor = new
{
seq = c.sequence,
lat = c.position.Latitude,
lon = c.position.Longitude
}
};

How to improve performance of SQL MERGE statement

I have a job that I am currenlty running to sync data between two databases on different internal servers. The one server is the backend database for the HEAT product from FrontRange. The second is our own reporting database we are using for report writing and other internal uses.
Our first approach at the job went something like this:
Query all the data from the HEAT database tables we wanted and populate local temp tables. Then copy that data out to the appropriate table. That would work but they use to TRUNCATE the table every time and repopulate without doing anything for indexes or fragmentation. So I thought well this could be a good candidate to use the SQL merge statement.
So our second approach used a merge statement for each of the tables. It greatly improved the speed of the process but it seems to be locking the source table up so that users are noticing 15-30 second delays when they try to save information. To make the merge only handle records that have had changes or are new I added the BINARY_CHECKSUM function on the select and store it on my side so that I can avoid updating records that haven't changed. Seems expensive though to call that for every record. This table has about ~300k records.
I am wondering is there a better approach to try and synchronize these two tables that I am overlooking. My only constraint is that I really do not want to change anything on the source tables because it is a third party application.
Here is my mege statement I am using for the CallLog table:
-- Merge CallLog
MERGE INTO [CallLog] AS T
USING (
SELECT
[CallID], [CustID], [CustType], [CallType], [Tracker], [CallStatus], [Priority], [CDuration], [CallCount], [StopWatch], [ClosedBy],
[ClosedDate], [ClosedTime], [Cause], [CallDesc], [CloseDesc], [RecvdBy], [RecvdDate], [RecvdTime], [ModBy], [ModDate], [ModTime],
[DTLastMod], [CallSource], [PriorityName], [QuickCall], [Category], [TotalAsgnmntTime], [CatHeading], [TotalJournalTime],
[TotalTime], [SL_Warn_Goal], [SL_Warn_Date], [SL_Warn_Time], [SL_Complete_Goal], [SL_Complete_Date], [SL_Complete_Time],
[SL_Clock_Status], [SL_Button_Status], [FirstResolution], [SL_Complete_Status], [SubCallType], [ImpactValue], [ImpactName],
[UrgencyValue], [UrgencyName], [LinkedToProblem], [LinkedToProblemCustID], [LinkedToProblemName], [LinkedToProblemBy],
[LinkedToProblemDate], [LinkedToProblemTime], [SLAStatus], [issue_text], [issue_number], [ResCheck], [AsgnAckBy], [AsgnAckDate],
[AsgnAckTime], [Resolvedby], [ResolvedDate], [ResolvedTime], [ACheck], [ACKEmail], [LinkedToChange], [LinkedToChangeCustID],
[LinkedToChangeName], [LinkedToChangeBy], [LInkedToChangeDate], [LinkedToChangeTime], [IssueTypeProblem], [IssueTypeChange],
[RespWarningD], [RespWarningT], [RespMissedD], [RespMissedT], [ResoWarningD], [ResoWarningT], [ResoMissedD], [ResoMissedT],
[IssueType], [SubCategory], [Diagnosis], [HSSAlert], [ErrorMessage], [ProblemType], [diagnosising], [KB], [CloseStatus],
[SuggestedAssignGrp], [DefaultGrp], [DefaultGrpTF], [OtherAssign], [WorkAround], [ChangeReason], [CloseProblem], [AssgnApp],
[AssgnAppRes], [DenyChk], [ImplementationApp], [ImplementationAppRes], [WorkAroundChk], [NoDenyChk], [ImpNoDenyChk],
[ImpDenyChk], [ChangeStatus], [ReadyToClose], [ResolveOrReAssign], [TicketLabel], [CatCallType], [IssueType_PK], [Category_PK],
[SubCategory_PK], [CallType_PK], [SubCallType_PK], BINARY_CHECKSUM(*) AS [Checksum]
FROM
[CHLA-HEATDB].SDIT.dbo.calllog
) AS S
ON (T.[CallID] = S.[CallID])
WHEN MATCHED AND T.[Checksum] <> S.[Checksum] THEN
UPDATE SET
T.[CallID] = S.[CallID], T.[CustID] = S.[CustID], T.[CustType] = S.[CustType], T.[CallType] = S.[CallType],
T.[Tracker] = S.[Tracker], t.[CallStatus] = S.[CallStatus], T.[Priority] = S.[Priority], T.[CDuration] = S.[CDuration],
T.[CallCount] = S.[CallCount], T.[StopWatch] = S.[StopWatch], T.[ClosedBy] = S.[ClosedBy],
T.[ClosedDate] = S.[ClosedDate], T.[ClosedTime] = S.[ClosedTime], T.[Cause] = S.[Cause], T.[CallDesc] = S.[CallDesc],
T.[CloseDesc] = S.[CloseDesc], T.[RecvdBy] = S.[RecvdBy], T.[RecvdDate] = S.[RecvdDate], T.[RecvdTime] = S.[RecvdTime],
T.[ModBy] = S.[ModBy], T.[ModDate] = S.[ModDate], T.[ModTime] = S.[ModTime], T.[DTLastMod] = S.[DTLastMod],
T.[CallSource] = S.[CallSource], T.[PriorityName] = S.[PriorityName], T.[QuickCall] = S.[QuickCall],
T.[Category] = S.[Category], T.[TotalAsgnmntTime] = S.[TotalAsgnmntTime], T.[CatHeading] = S.[CatHeading],
T.[TotalJournalTime] = S.[TotalJournalTime], T.[TotalTime] = S.[TotalTime], T.[SL_Warn_Goal] = S.[SL_Warn_Goal],
T.[SL_Warn_Date] = S.[SL_Warn_Date], T.[SL_Warn_Time] = S.[SL_Warn_Time], T.[SL_Complete_Goal] = S.[SL_Complete_Goal],
T.[SL_Complete_Date] = S.[SL_Complete_Date], T.[SL_Complete_Time] = S.[SL_Complete_Time],
T.[SL_Clock_Status] = S.[SL_Clock_Status], T.[SL_Button_Status] = S.[SL_Button_Status],
T.[FirstResolution] = S.[FirstResolution], T.[SL_Complete_Status] = S.[SL_Complete_Status],
T.[SubCallType] = S.[SubCallType], T.[ImpactValue] = S.[ImpactValue], T.[ImpactName] = S.[ImpactName],
T.[UrgencyValue] = S.[UrgencyValue], T.[UrgencyName] = S.[UrgencyName], T.[LinkedToProblem] = S.[LinkedToProblem],
T.[LinkedToProblemCustID] = S.[LinkedToProblemCustID], T.[LinkedToProblemName] = S.[LinkedToProblemName],
T.[LinkedToProblemBy] = S.[LinkedToProblemBy], T.[LinkedToProblemDate] = S.[LinkedToProblemDate],
T.[LinkedToProblemTime] = S.[LinkedToProblemTime], T.[SLAStatus] = S.[SLAStatus], T.[issue_text] = S.[issue_text],
T.[issue_number] = S.[issue_number], T.[ResCheck] = S.[ResCheck], T.[AsgnAckBy] = S.[AsgnAckBy],
T.[AsgnAckDate] = S.[AsgnAckDate], T.[AsgnAckTime] = S.[AsgnAckTime], T.[Resolvedby] = S.[Resolvedby],
T.[ResolvedDate] = S.[ResolvedDate], T.[ResolvedTime] = S.[ResolvedTime], T.[ACheck] = S.[ACheck],
T.[ACKEmail] = S.[ACKEmail], T.[LinkedToChange] = S.[LinkedToChange], T.[LinkedToChangeCustID] = S.[LinkedToChangeCustID],
T.[LinkedToChangeName] = S.[LinkedToChangeName], T.[LinkedToChangeBy] = S.[LinkedToChangeBy],
T.[LInkedToChangeDate] = S.[LInkedToChangeDate], T.[LinkedToChangeTime] = S.[LinkedToChangeTime],
T.[IssueTypeProblem] = S.[IssueTypeProblem], T.[IssueTypeChange] = S.[IssueTypeChange],
T.[RespWarningD] = S.[RespWarningD], T.[RespWarningT] = S.[RespWarningT], T.[RespMissedD] = S.[RespMissedD],
T.[RespMissedT] = S.[RespMissedT], T.[ResoWarningD] = S.[ResoWarningD], T.[ResoWarningT] = S.[ResoWarningT],
T.[ResoMissedD] = S.[ResoMissedD], T.[ResoMissedT] = S.[ResoMissedT], T.[IssueType] = S.[IssueType],
T.[SubCategory] = S.[SubCategory], T.[Diagnosis] = S.[Diagnosis], T.[HSSAlert] = S.[HSSAlert],
T.[ErrorMessage] = S.[ErrorMessage], T.[ProblemType] = S.[ProblemType], T.[diagnosising] = S.[diagnosising],
T.[KB] = S.[KB], T.[CloseStatus] = S.[CloseStatus], T.[SuggestedAssignGrp] = S.[SuggestedAssignGrp],
T.[DefaultGrp] = S.[DefaultGrp], T.[DefaultGrpTF] = S.[DefaultGrpTF], T.[OtherAssign] = S.[OtherAssign],
T.[WorkAround] = S.[WorkAround], T.[ChangeReason] = S.[ChangeReason], T.[CloseProblem] = S.[CloseProblem],
T.[AssgnApp] = S.[AssgnApp], T.[AssgnAppRes] = S.[AssgnAppRes], T.[DenyChk] = S.[DenyChk],
T.[ImplementationApp] = S.[ImplementationApp], T.[ImplementationAppRes] = S.[ImplementationAppRes],
T.[WorkAroundChk] = S.[WorkAroundChk], T.[NoDenyChk] = S.[NoDenyChk], T.[ImpNoDenyChk] = S.[ImpNoDenyChk],
T.[ImpDenyChk] = S.[ImpDenyChk], T.[ChangeStatus] = S.[ChangeStatus], T.[ReadyToClose] = S.[ReadyToClose],
T.[ResolveOrReAssign] = S.[ResolveOrReAssign], T.[TicketLabel] = S.[TicketLabel], T.[CatCallType] = S.[CatCallType],
T.[IssueType_PK] = S.[IssueType_PK], T.[Category_PK] = S.[Category_PK], T.[SubCategory_PK] = S.[SubCategory_PK],
T.[CallType_PK] = S.[CallType_PK], T.[SubCallType_PK] = S.[SubCallType_PK], T.[Checksum] = S.[Checksum]
WHEN NOT MATCHED
THEN INSERT VALUES
(
S.[CallID], S.[CustID], S.[CustType], S.[CallType], S.[Tracker], S.[CallStatus], S.[Priority], S.[CDuration],
S.[CallCount], S.[StopWatch], S.[ClosedBy], S.[ClosedDate], S.[ClosedTime], S.[Cause], S.[CallDesc], S.[CloseDesc],
S.[RecvdBy], S.[RecvdDate], S.[RecvdTime], S.[ModBy], S.[ModDate], S.[ModTime], S.[DTLastMod], S.[CallSource],
S.[PriorityName], S.[QuickCall], S.[Category], S.[TotalAsgnmntTime], S.[CatHeading], S.[TotalJournalTime], S.[TotalTime],
S.[SL_Warn_Goal], S.[SL_Warn_Date], S.[SL_Warn_Time], S.[SL_Complete_Goal], S.[SL_Complete_Date], S.[SL_Complete_Time],
S.[SL_Clock_Status], S.[SL_Button_Status], S.[FirstResolution], S.[SL_Complete_Status], S.[SubCallType], S.[ImpactValue],
S.[ImpactName], S.[UrgencyValue], S.[UrgencyName], S.[LinkedToProblem], S.[LinkedToProblemCustID], S.[LinkedToProblemName],
S.[LinkedToProblemBy], S.[LinkedToProblemDate], S.[LinkedToProblemTime], S.[SLAStatus], S.[issue_text], S.[issue_number],
S.[ResCheck], S.[AsgnAckBy], S.[AsgnAckDate], S.[AsgnAckTime], S.[Resolvedby], S.[ResolvedDate], S.[ResolvedTime], S.[ACheck],
S.[ACKEmail], S.[LinkedToChange], S.[LinkedToChangeCustID], S.[LinkedToChangeName], S.[LinkedToChangeBy],
S.[LInkedToChangeDate], S.[LinkedToChangeTime], S.[IssueTypeProblem], S.[IssueTypeChange], S.[RespWarningD],
S.[RespWarningT], S.[RespMissedD], S.[RespMissedT], S.[ResoWarningD], S.[ResoWarningT], S.[ResoMissedD], S.[ResoMissedT],
S.[IssueType], S.[SubCategory], S.[Diagnosis], S.[HSSAlert], S.[ErrorMessage], S.[ProblemType], S.[diagnosising], S.[KB],
S.[CloseStatus], S.[SuggestedAssignGrp], S.[DefaultGrp], S.[DefaultGrpTF], S.[OtherAssign], S.[WorkAround], S.[ChangeReason],
S.[CloseProblem], S.[AssgnApp], S.[AssgnAppRes], S.[DenyChk], S.[ImplementationApp], S.[ImplementationAppRes],
S.[WorkAroundChk], S.[NoDenyChk], S.[ImpNoDenyChk], S.[ImpDenyChk], S.[ChangeStatus], S.[ReadyToClose],
S.[ResolveOrReAssign], S.[TicketLabel], S.[CatCallType], S.[IssueType_PK], S.[Category_PK], S.[SubCategory_PK],
S.[CallType_PK], S.[SubCallType_PK], S.[Checksum]
);
GO
Since you're on SQL 2008, how about Change Data Capture? You can get the net changes over a period of time and deal only with that (as opposed to replication which pushes every change, even if you update the same data 10 times).
I think you can improve performance by figuring out what rows to modify/insert before the merge statement.
You can create a temp table that contains the CallID's that should be affected.
Perhaps something like this.
;with cteSource as
(
select
S.CallID,
binary_checksum(*) as [CheckSum]
from [CHLA-HEATDB].SDIT.dbo.calllog
)
select
S.CallID,
S.[CheckSum]
into #TmpSource
from cteSource as S
left outer join CallLog as T
on S.CallID = T.CallID and
S.[CheckSum] = T.[CheckSum]
where T.CallID is null
Then you can use that table in your using select statement.
MERGE INTO [CallLog] AS T
USING (
SELECT
[CallID],
-- A lot of fields
T.[CheckSum] AS [Checksum]
FROM
[CHLA-HEATDB].SDIT.dbo.calllog as C
inner join #TmpSource as Tmp
on C.CallID = Tmp.CallID
) AS S
ON (T.[CallID] = S.[CallID])
WHEN MATCHED THEN -- Probably don't need this AND T.[Checksum] <> S.[Checksum] THEN
UPDATE SET
T.[CallID] = S.[CallID],
-- More fields here
WHEN NOT MATCHED
THEN INSERT VALUES
(
S.[CallID],
-- More fields here
);

I have some quite simple SQL that I can trying to change to either Linq or LLBLGEN

I want to do something like this...
SELECT DISTINCT T1.*
FROM T1
INNER JOIN T2 ON T2.ID1 = T1.ID1
INNER JOIN T3 ON T3.ID2 = T2.ID2
--FOLLOWING CAN BE ADDED MULTIPLE TIMES (LOOPS IN C#?)
INNER JOIN T2 AS T2A ON T3.ID2 = T2A.ID2
INNER JOIN T1 AS T1A ON T1A.ID1 = T2A.ID1
--END MULTI
WHERE T1.ID1 = 1
AND T3.ID3 = 2
AND T3.ID4 = 3
--THE FOLLOWING CONDITIONS WILL ALSO BE FOR EVERY SET OF EXTRA JOINS (LOOPS IN C#?)
AND T1A.ID1 = 4
AND T1I.ID5 = 5
--END MULTI
...in either Linq or LLBLGen Code. Any help would be greatly appreciated!
Here is the LLBGen I have so far...
IPredicateExpression filter = new PredicateExpression();
filter.Add(ProductTypeOptionAttributeFields.OptionId == dl.Key);
filter.AddWithAnd(ProductTypeOptionAttributeCombinationFields.ProductTypeId == DataSource.DataItem.ProductTypeId);
filter.AddWithAnd(ProductTypeOptionAttributeCombinationFields.ProductId == DataSource.ProductID);
bucket.PredicateExpression.Add(filter);
bucket.Relations.Add(ProductTypeOptionAttributeEntity.Relations.ProductTypeOptionAttributeCombinationProfileEntityUsingProductTypeOptionAttributeId, JoinHint.Inner);
bucket.Relations.Add(ProductTypeOptionAttributeCombinationProfileEntity.Relations.ProductTypeOptionAttributeCombinationEntityUsingProductTypeOptionAttributeCombinationId, JoinHint.Inner);
var filtered = _dropdowns.Where(k => ((DropDownList)k.Value[1]).SelectedValue != "-1" && k.Key != dl.Key);
foreach (var filteredDdl in filtered)
{
IPredicateExpression subFilter = new PredicateExpression();
subFilter.AddWithAnd(ProductTypeOptionAttributeFields.AttributeId == int.Parse(((DropDownList)filteredDdl.Value[1]).SelectedValue));
subFilter.AddWithAnd(ProductTypeOptionAttributeFields.OptionId == filteredDdl.Key);
bucket.PredicateExpression.AddWithAnd(subFilter);
}
ProductTypeOptionAttributeCollection attrs = new ProductTypeOptionAttributeCollection();
attrs.GetMulti(bucket.PredicateExpression, -1, null, bucket.Relations);
And here is the actual query I want...
SELECT DISTINCT PTOA.*
FROM ProductTypeOptionAttribute AS PTOA
INNER JOIN ProductTypeOPtionAttributeCombinationProfile AS PTOACP ON PTOACP.ProductTypeOPtionAttributeID = PTOA.AttributeID
INNER JOIN ProductTypeOPtionAttributeCombination AS PTOAC ON PTOAC.CombinationID = PTOACP.ProductTypeOptionAttributeCombinationID
--FOLLOWING CAN BE ADDED MULTIPLE TIMES (LOOPS IN C#?)
INNER JOIN ProductTypeOPtionAttributeCombinationProfile AS PTOACP2 ON PTOAC.CombinationID = PTOACP2.ProductTypeOptionAttributeCombinationID
INNER JOIN ProductTypeOPtionAttribute AS PTOA2 ON PTOACP2.ProductTypeOPtionAttributeID = PTOA2.AttributeID
--END MULTI
WHERE PTOA.OptionID = 59
AND PTOAC.ProductTypeID = 11
AND PTOAC.ProductID = 218
--THE FOLLOWING CONDITIONS WILL ALSO BE FOR EVERY SET OF EXTRA JOINS (LOOPS IN C#?)
AND PTOA2.AttributeID = 42
AND PTOA2.OptionID = 58
--END MULTI
Cheers
LLBLGen Tips:
Use SQL Server Profiler to view the SQL emitted (set a breakpoint right after your call to GetMulti, then watch your trace)
You have a lot of complicated UI login and cast/converts that could fail -- my personal preference would be to move those to separate code
You don't need JoinHint.Inner as that is the default
(Personal preference) use a RelationCollection instead of the bucket.
I don't entirely understand your situation (especially the multiple joins to the same table?), but this may work. I think you want subFilter.AddWithOr instead of .AddWithAnd.
IPredicateExpression filter = new PredicateExpression();
filter.Add(ProductTypeOptionAttributeFields.OptionId == dl.Key);
filter.AddWithAnd(ProductTypeOptionAttributeCombinationFields.ProductTypeId == DataSource.DataItem.ProductTypeId);
filter.AddWithAnd(ProductTypeOptionAttributeCombinationFields.ProductId == DataSource.ProductID);
IRelationCollection relations = new RelationCollection();
relations.Add(ProductTypeOptionAttributeEntity.Relations.ProductTypeOptionAttributeCombinationProfileEntityUsingProductTypeOptionAttributeId);
relations.Add(ProductTypeOptionAttributeCombinationProfileEntity.Relations.ProductTypeOptionAttributeCombinationEntityUsingProductTypeOptionAttributeCombinationId);
var filtered = _dropdowns.Where(k => ((DropDownList)k.Value[1]).SelectedValue != "-1" && k.Key != dl.Key);
foreach (var filteredDdl in filtered)
{
IPredicateExpression subFilter = new PredicateExpression();
subFilter.AddWithOr(ProductTypeOptionAttributeFields.AttributeId == int.Parse(((DropDownList)filteredDdl.Value[1]).SelectedValue));
subFilter.AddWithOr(ProductTypeOptionAttributeFields.OptionId == filteredDdl.Key);
filter.AddWithAnd(subFilter);
}
ProductTypeOptionAttributeCollection attrs = new ProductTypeOptionAttributeCollection();
attrs.GetMulti(filter, relations)
The basic SQL query you presented should be faily easy to reproduce in LINQ.
From t in T1
Where T1.ID == 1
Select;
if your not already using it download the free LINQPAD http://www.linqpad.net/ Its got loads of examples to get you up to speed.