SQL to Linq-Entities - entity-framework-4

Please help me to convert this SQL query in LINQ-Enitites
select e.RowMeterialName,f.RowUnitName,*,isnull((b.Quantity - (Select SUM(a.Quantity) from PurchaseDetail a
join PurchaseMaster c on a.PurchaseId=c.PurchaseId
where a.RawMetId=b.RawMetrialId and c.PurchaseOrderId=b.PurchaseOrderId)),b.Quantity) as Remain
from PurchaseOrderDetail b
join RawMeterialMaster e on b.RawMetrialId=e.RawMetId
join RawUnitMaster f on e.RawUnitId=f.RowUnitId
where b.PurchaseOrderId=#PurchaseOrderId
Please help me.

This is a long shot, but you can try it:
PurchaseDetail
.Join
(
PurchaseMaster,
x=>x.PurchaseId,
x=>x.PurchaseId,
(detail,master)=>new {detail,master}
)
.Join
(
PurchaseOrderMaster,
x=>x.PurchaseOrderId,
x=>x.PurchaseOrderId,
(joined,ordermaster)=>new{detail=joined.detail,master=joined.master,ordermaster}
)
.Select
(
x=>
new{detail.Quantity,detail.RawMetId}
)
.GroupBy(x=>x.RawMetId)
.Select
(
x=>
new
{
RawMetId=x.Key,
Quantity=x.Sum(z=>z.Quantity)
}
)
.Join
(
PurchaseOrderDetail,
x=>x.RawMetrialId,
x=>x.RawMetId,
(subquery,orderdetail)=>new{subquery,Remain=subquery.Quantity - orderdetail.Quantity}
)

Thanks everybody but I found the result with this query
from b in db.PurchaseOrderDetails
select new
{
b.RawMeterialMaster.RowMeterialName,
PurOrderDetailId = b.PurOrderDetailId,
PurchaseOrderId = b.PurchaseOrderId,
RawMetrialId = b.RawMetrialId,
DueOn = b.DueOn,
Quantity = b.Quantity,
ItemRate = b.ItemRate,
MetrialUnitsId = b.MetrialUnitsId,
Remark = b.Remark,
RowUnitName = b.RawMeterialMaster.RawUnitMaster.RowUnitName,
ReOrderQuantity = (decimal?)b.RawMeterialMaster.ReOrderQuantity,
Remain = ((System.Decimal?)b.Quantity -
(from a in db.PurchaseDetails
where
a.RawMetId == b.RawMetrialId &&
a.PurchaseMaster.PurchaseOrderId == b.PurchaseOrderId
select new
{
a.Quantity
}).Sum(p => p.Quantity) ?? (System.Decimal?)b.Quantity)
};

Related

Getting parameter in ADO.Net exception when calling from angular

I had created an API in Dot net core. When I had tested it's working well & good through postman or ARC tools. But when calling from angular, It's throwing an sqlexception like : "An SqlParameter with parameter name #TotalRows is not contained by the SqlParameterCollection."
My wonder is how it's working in postman & why not in angular call.
My API dataaccess is like below :
public List<PoDetails> GetPoDetails(PoDetails pods, string vendor_id, out int TotalRows, int Timezone)
{
List<PoDetails> posList = new List<PoDetails>();
TotalRows = 0;
try
{
con = new SqlConnection(conString);
cmd = new SqlCommand("sp_cc_get_po_details", con);
cmd.Parameters.Clear();
cmd.CommandType = CommandType.StoredProcedure;
cmd = Util.AddConditionalParameterString(cmd, "#vendor_id", vendor_id);
cmd = Util.AddConditionalParameterString(cmd, "#sortBy", pods.sortBy);
cmd = Util.AddConditionalParameterString(cmd, "#sortDirection", pods.sortDirection);
cmd = Util.AddConditionalParameterInt(cmd, "#pageSize", pods.pageSize);
cmd = Util.AddConditionalParameterInt(cmd, "#page", pods.page);
cmd = Util.AddConditionalParameterInt(cmd, "#time_zone_offset", Timezone);
cmd.Parameters.Add(new SqlParameter("#TotalRows", SqlDbType.Int));
cmd.Parameters["#TotalRows"].Direction = ParameterDirection.Output;
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
TotalRows = Convert.ToInt32(cmd.Parameters["#TotalRows"].Value);
foreach (DataRow dr in dt.Rows)
{
PoDetails posobj = new PoDetails();
posobj.vendor_name = dr["vendor_name"].ToString();
posobj.create_date = Convert.ToDateTime(dr["create_date"].ToString());
posobj.po_id = Convert.ToInt32(dr["po_id"]);
posobj.po_amount = Convert.ToInt32(dr["po_amount"]);
posobj.invoice_count = Convert.ToInt32(dr["invoicecount"]);
if (dr["utilization_amount"] != DBNull.Value)
posobj.utilization_amount = Convert.ToInt32(dr["utilization_amount"]);
else
posobj.utilization_amount = 0;
posList.Add(posobj);
}
}
catch (Exception ec)
{
throw new Exception(ec.Message);
}
return posList;
}
My procedure was like below :
ALTER PROCEDURE [dbo].[sp_cc_get_po_details]
(
#vendor_id varchar(100) = null,
#sortBy varchar(50) = NULL,
#sortDirection varchar(50) = null,
#pageSize int = NULL,
#page int = NULL,
#TotalRows int = NULL output,
#time_zone_offset int = 0
)
AS
BEGIN
SELECT Count(I.invoice_id) as invoicecount, p.po_id,p.po_amount,p.vendor_id,
DATEADD(MINUTE, #time_zone_offset, p.create_date) AS create_date ,
v.vendor_name, sum(I.invoice_amount) as utilization_amount
into #TempResults
FROM po_details p left join invoice_details I on p.po_id = I.po_id
join vendor_details v on v.vendor_id = p.vendor_id
WHERE (#vendor_id is null or #vendor_id = '' or v.vendor_id = #vendor_id)
group by p.po_id, p.po_amount, p.vendor_id, p.create_date, v.vendor_name
-- Paging Logic --
Declare #StartingRow as int = 0
Declare #FirstRow as int
Declare #LastRow as int
select #TotalRows = count(*)
from #TempResults
set #StartingRow = (#pageSize * #page) + 1
if #pageSize is not null and #page is not null begin
set #FirstRow = ((#page - 1) * #pageSize) + 1
set #LastRow = #FirstRow + (#pageSize - 1)
end else if #pageSize is not null and #StartingRow is not null begin
set #FirstRow = #StartingRow
set #LastRow = #FirstRow + (#pageSize - 1)
end else begin
set #FirstRow = 0
set #LastRow = #TotalRows
end
------
-------------------
--select #FirstRow;
--select #LastRow;
Select * from
(
Select ROW_NUMBER() over
(
order by
case when #sortBy = 'vendor_id' and #sortDirection = 'desc' then vendor_id end desc,
case when #sortBy = 'vendor_id' and #sortDirection = 'asc' then vendor_id end asc,
case when #sortBy = 'vendor_name' and #sortDirection = 'desc' then vendor_name end desc,
case when #sortBy = 'vendor_name' and #sortDirection = 'asc' then vendor_name end asc,
vendor_id
) as RowNumber, * from #TempResults
) RowData
where RowNumber between #FirstRow and #LastRow
order by RowNumber
end

Can you see anything in this foreach loop that would make it execute twice?

This is "psuedo code" from a workflow that I hope will be more readable than xaml or the design view. The top foreach loop "foreach (DataRow row in dataSetTables[0] as Enumerable())" seems to be executing twice. At least the 2 Rest Calls and the DB insert operation contained inside it are happening twice. I've no idea why a foreach would execute twice.
drpQryStr = "very long query string"
dataSet = new DataSet()
dataSet = ExecuteQuery
if dataSet.Tables[0].Rows.Count > 0
foreach (DataRow row in dataSetTables[0] as Enumerable())
iter = 0
dict = new Dictionary<string, string>()
lst = new List<char>()
newDict = new Dictionary<string, string>()
sb = new StringBuilder()
Do
dict.Add(row.Table.Columns[iter].ColumnName, row[row.Table.Columns[iter].ColumnName].ToString())
iter ++
While(iter < row.Table.Columns.Count)
foreach (KeyValuePair kv in dict)
if(kv.Key == "DOB" || kv.Key == "LOB")
newDict.Add(kv.Key, kv.Value)
else
strKey = kv.Key
strCaseCorrected = strKey.ToLower()
aChars = strCaseCorrected.ToCharArray()
lst.Clear()
sb.Clear()
lst.AddRange(aChars)
itr2 = 0
Do
if(itr2 == 0)
lst[itr2] = Char.ToUpper(lst[itr2])
else
if(lst[itr2] == '_')
itr2 ++
lst[itr2] = Char.ToUpper(lst[itr2])
else
if(lst.Count - itr2 == 1)
if(lst[itr2] == 'd')
if(lst[itr2 - 1] == 'I')
lst[itr2] = 'D'
itr2 ++
While(itr2 < lst.Count)
foreach(Char c in lst)
sb.Append(c.ToStrng()
newDict.Add(sb.ToString(), kv.Value)
dict = newDict
dict[Communiction_Date] = dict["Communication_Date"].Insert(4, "-").Insert(7, "-")
strJson = JsonConvert.SerializeObject(dict, Formatting.None)
today = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss")
Invoke a Rest Service that posts this json to a sqlless DB
eventStr = "a large string that likely doesn't cause the problem"
ctdbObj = JObject.Parse(eventStr)
Invoke aRest Service that Posts an event to a sqlless DB
cts_id = dict["External_Source_ID"]
strInsert = "sql insert statement"
Execute Insert statement
SendResponse
Yeah neither could I, I thnk the sql query may be running too long and the workflow is being invoked again before it finishes executing. Consider this closed.

Typo3 7.6 extbase repository matching only affect non-localized records

I want to create an own extbase extension for TYPO3 CMS 7.6. The extension has to run in different languages. I figured out, that the repository matching does only work for me with non-localized records.
My repository function looks like that:
public function findNew() {
$query = $this->createQuery();
$query->getQuerySettings()->setRespectSysLanguage(true);
$query->matching($query->equals('new', 1));
return $query->execute();
}
This function says: Show all records with new = 1
Example:
I have a default record that has the checkbox "New" NOT activated. Now I create a localized version of this record and set the "New" checkbox to activated.
If I execute the function findNew() in the default language, the record will not show up. If I execute the function in another language, the record will also not show up although the "New"-flag is set!
In other words: The matching does only affect the default/parent record.
I'm using the following config-settings:
config {
sys_language_mode = strict
sys_language_overlay = hideNonTranslated
}
[Edit:]
Here's the complete generated SQL query:
SELECT tx_extension_domain_model_table.*
FROM
tx_extension_domain_model_table
WHERE
tx_extension_domain_model_table.new = '1'
AND (
tx_extension_domain_model_table.sys_language_uid = -1
OR (
tx_extension_domain_model_table.sys_language_uid = 1
AND tx_extension_domain_model_table.l10n_parent = 0
)
OR (
tx_extension_domain_model_table.sys_language_uid = 0
AND tx_extension_domain_model_table.uid IN (
SELECT tx_extension_domain_model_table.l10n_parent
FROM tx_extension_domain_model_table
WHERE tx_extension_domain_model_table.l10n_parent > 0
AND tx_extension_domain_model_table.sys_language_uid = 1
AND tx_extension_domain_model_table.deleted = 0
)
)
)
AND tx_extension_domain_model_table.deleted = 0
AND tx_extension_domain_model_table.t3ver_state <= 0
AND tx_extension_domain_model_table.pid <> -1
AND tx_extension_domain_model_table.hidden = 0
AND tx_extension_domain_model_table.starttime <= 1459780380
AND (tx_extension_domain_model_table.endtime = 0 OR tx_extension_domain_model_table.endtime > 1459780380)
ORDER BY tx_extension_domain_model_table.sorting ASC
...and the important part:
AND (
tx_extension_domain_model_table.sys_language_uid = -1
OR (
tx_extension_domain_model_table.sys_language_uid = 1
AND tx_extension_domain_model_table.l10n_parent = 0
)
OR (
tx_extension_domain_model_table.sys_language_uid = 0
AND tx_extension_domain_model_table.uid IN (
SELECT tx_extension_domain_model_table.l10n_parent
FROM tx_extension_domain_model_table
WHERE tx_extension_domain_model_table.l10n_parent > 0
AND tx_extension_domain_model_table.sys_language_uid = 1
AND tx_extension_domain_model_table.deleted = 0
)
)
)
That explains my problem. TYPO3 is not looking for new = 1 in sys_language_uid = 1 when it's localized... but why?
Question: Is this a bug or a feature?
It's a bug in extbase, see here for more information: https://forge.typo3.org/issues/57272

Advanced query range

How to make a query in Ax with advanced filtering (with x++):
I want to make such filter criteria On SalesTable form to show SalesTable.SalesId == "001" || SalesLine.LineAmount == 100.
So result should show SalesOrder 001 AND other salesOrders which has at least one SalesLine with LineAmount = 100?
Jan's solution works fine if sales order '001' should only be selected if it has sales lines. If it doesn't have lines it won't appear in the output.
If it is important to you that sales order '001' should always appear in the output even if it doesn't have sales lines, you can do it via union as follows:
static void AdvancedFiltering(Args _args)
{
Query q;
QueryRun qr;
QueryBuildDataSource qbds;
SalesTable salesTable;
;
q = new Query();
q.queryType(QueryType::Union);
qbds = q.addDataSource(tablenum(SalesTable), identifierstr(SalesTable_1));
qbds.fields().dynamic(false);
qbds.fields().clearFieldList();
qbds.fields().addField(fieldnum(SalesTable, SalesId));
qbds.addRange(fieldnum(SalesTable, SalesId)).value(queryValue('001'));
qbds = q.addDataSource(tablenum(SalesTable), identifierstr(SalesTable_2), UnionType::Union);
qbds.fields().dynamic(false);
qbds.fields().clearFieldList();
qbds.fields().addField(fieldnum(SalesTable, SalesId));
qbds = qbds.addDataSource(tablenum(SalesLine));
qbds.relations(true);
qbds.joinMode(JoinMode::ExistsJoin);
qbds.addRange(fieldnum(SalesLine, LineAmount )).value(queryValue(100));
qr = new QueryRun(q);
while (qr.next())
{
salesTable = qr.get(tablenum(SalesTable));
info(salesTable.SalesId);
}
}
The AX select statement supports exists join such as:
while select salesTable
exits join salesLine
where salesLine.SalesId == salesTable.SalesId &&
salesLine.LineAmount == 100
X++ does not support exists clause as a subquery in the where clause. Therefore it is not possible to express the exists in combination with or.
However AX supports query expressions in a query.
Therefore your query should be possible to express like this:
static void TestQuery(Args _args)
{
SalesTable st;
QueryRun qr = new QueryRun(new Query());
QueryBuildDataSource qst = qr.query().addDataSource(tableNum(SalesTable));
QueryBuildDataSource qsl = qst.addDataSource(tableNum(SalesLine));
str qstr = strFmt('((%1.SalesId == "%2") || (%3.LineAmount == %4))',
qst.name(), queryValue("001"),
qsl.name(), queryValue(100));
qsl.relations(true); // Link on SalesId
qsl.joinMode(JoinMode::ExistsJoin);
qsl.addRange(fieldNum(SalesLine,RecId)).value(qstr);
info(qstr); // This is the query expression
info(qst.toString()); // This is the full query
while (qr.next())
{
st = qr.get(tableNum(SalesTable));
info(st.SalesId);
}
}
However, if sales order 001 does not contain lines, it will not be selected.
Other than that the output is as you requested:
((SalesTable_1.SalesId == "001") || (SalesLine_1.LineAmount == 100))
SELECT FIRSTFAST * FROM SalesTable
EXISTS JOIN FIRSTFAST * FROM SalesLine WHERE SalesTable.SalesId =
SalesLine.SalesId AND ((((SalesTable_1.SalesId == "001") ||
(SalesLine_1.LineAmount == 100))))
001
125
175

Make good LINQ query with string[]

I have some problems with LINQ and maby someone got answers
string[] roleNames = Roles.GetRolesForUser(currentUserName);
result = context.MenuRoles.Select(mr => new MenuGenerateViewModel
{
MenuID = mr.MenuID,
MenuNazwa = mr.Menu.MenuNazwa,
MenuKolejnosc = mr.Menu.MenuKolejnosc,
MenuStyl = mr.Menu.MenuStyl,
MenuParentID = mr.Menu.MenuParentID,
MenuActive = mr.Menu.MenuActive,
MenuActionName = mr.Menu.MenuAction.MenuActionName,
MenuControlName = mr.Menu.MenuControl.MenuControlName,
RoleName = mr.Role.RoleName,
RoleID = mr.RoleID,
MenuID = mr.MenuID
})
.Where(mr => mr.MenuActive == true)
.ToList();
How to take only compare string[] roleNames and return only if match. Problem alwais is when user is in the 2 or more roles.
Tx for answers
If I understand what you are asking for, add a second condition to your Where clause:
.Where(mr => mr.MenuActive && roleNames.Contains(mr.Role.RoleName))
You would be better off switching round your Where clause and Select for the simple reason that then you will not be retrieving from the database records which are not required.
result = context.MenuRoles.Where(mr => mr.MenuActive
&& roleNames.Contains(mr.Role.RoleName))
.Select(mr => ... )
.ToList();
This will generate a sql which only selects the necessary records, instead of selecting the whole lot and then filtering it. Try it and watch SQL profiler to see the difference (useful skill in any case when using EF)
With the help of brilliant people here, reached the target.
string[] roleNames = Roles.GetRolesForUser(currentUserName);
result = context.MenuRoles
.Where(mr => mr.Menu.MenuActive && roleNames.Contains(mr.Role.RoleName))
.Select(mr => new MenuGenerateViewModel
{
MenuID = mr.MenuID,
MenuNazwa = mr.Menu.MenuNazwa,
MenuKolejnosc = mr.Menu.MenuKolejnosc,
MenuStyl = mr.Menu.MenuStyl,
MenuParentID = mr.Menu.MenuParentID,
MenuActive = mr.Menu.MenuActive,
MenuActionName = mr.Menu.MenuAction.MenuActionName,
MenuControlName = mr.Menu.MenuControl.MenuControlName,
RoleName = mr.Role.RoleName
})
.ToList();
var userresult = context.MenuUsers
.Where(mr => mr.Menu.MenuActive && mr.User.Username == currentUserName)
.Select(mr => new MenuGenerateViewModel
{
MenuID = mr.MenuID,
MenuNazwa = mr.Menu.MenuNazwa,
MenuKolejnosc = mr.Menu.MenuKolejnosc,
MenuStyl = mr.Menu.MenuStyl,
MenuParentID = mr.Menu.MenuParentID,
MenuActive = mr.Menu.MenuActive,
MenuActionName = mr.Menu.MenuAction.MenuActionName,
MenuControlName = mr.Menu.MenuControl.MenuControlName,
Username = mr.User.Username
})
.ToList();
Here, gets all the menu to which you have the right, both through group membership and assigned directly to the menu itself.
// Kick all duplicates
var noduplicates = result.Concat(userresult)
.Distinct(new RoleMenuGenerateComparer());
Because usually we do not want duplicates in the menu so we remove them. For this to work properly we need to implement IEqualityComparer (U can read about this little bit up)
public class RoleMenuGenerateComparer : IEqualityComparer<MenuGenerateViewModel>
{
public bool Equals(MenuGenerateViewModel x, MenuGenerateViewModel y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.MenuNazwa == y.MenuNazwa && x.MenuID == y.MenuID;
}
public int GetHashCode(MenuGenerateViewModel menuGenerateViewModel)
{
if (Object.ReferenceEquals(menuGenerateViewModel, null)) return 0;
int hashMenuName = menuGenerateViewModel.MenuNazwa == null ? 0 : menuGenerateViewModel.MenuNazwa.GetHashCode();
int hashMenuID = menuGenerateViewModel.MenuID == null ? 0 : menuGenerateViewModel.MenuID.GetHashCode();
return hashMenuName ^ hashMenuID;
}
}
Of course I believe that you can optimize this code, but for the moment I have something like this.
Tx all for help.

Resources