Magento grid, getting incorrect total value - magento

I created a grid. Issues is i am getting total number of records incorrectly. But all the records are in the grid.
I tried in grid.html $this->getCollection()->getSize() code and it returns the incorrect value.
But count($this->getCollection()) returns the correct value. How can i solve this issues with $this->getCollection()->getSize().
Can anyone help me please.
Thank You

This is the classic case of using a group by clause or a having clause (or both) on your collection. Magento's getSelectCountSql function does not account for the group by or the having clause because of its poor frontend performance. Instead it generally uses indeces and statistics. However, if you would like to you can override your collection's getSelectCountSql as follows:
public function getSelectCountSql($select) {
$countSelect = clone $select;
$countSelect->reset(Zend_Db_Select::ORDER);
$countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
$countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
if ($select->getPart(Zend_Db_Select::HAVING)) {
//No good way to chop this up, so just subquery it
$subQuery = new Zend_Db_Expr("(".$countSelect->__toString().")");
$countSelect
->reset()
->from(array('temp' => $subQuery))
->reset(Zend_Db_Select::COLUMNS)
->columns('COUNT(*)')
;
} else {
$countSelect->reset(Zend_Db_Select::COLUMNS);
// Count doesn't work with group by columns keep the group by
if (count($select->getPart(Zend_Db_Select::GROUP)) > 0) {
$countSelect->reset(Zend_Db_Select::GROUP);
$countSelect->distinct(true);
$group = $select->getPart(Zend_Db_Select::GROUP);
$countSelect->columns("COUNT(DISTINCT ".implode(", ", $group).")");
} else {
$countSelect->columns('COUNT(*)');
}
}
return $countSelect;
}
This should return the correct number from getSize

Related

How to distinct a duplicate row in EF Core 6 with method syntax?

I want to query my database where I am searching a contract id by grouping them with LcNoListId. It is possible to contains duplicate value in LcNoListId column against a contract id. At this point I need to distinct all the duplicate LcNoListId and need to return without duplicate record.
I tried the below function for returning rows without duplicate value in LcNoListId column. But the Distinct() function is not working.
[HttpGet("contract-no/{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public IActionResult Get(int id)
{
try
{
IEnumerable<BTBPending> objBTBPendingList = _unitOfWork.BTBPending.GetAll(includeProperties: "ProformaInvoice,ContractList,SupplierList,CountryList,ItemList,BuyerList,StyleList,TradeTermList,ErpRemarksList,StatusList,LcNoList,UdAmendList");
var query = objBTBPendingList
.Where(x => x.ContractListId == id && x.UdAmendList == null)
.GroupBy(c => c.LcNoListId)
.Where(grp => grp.Distinct().Count() > 1);
// var que = Company.Distinct();
return Ok(query);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Something went wrong in the {nameof(Get)}");
return StatusCode(500, "Internal Server Error, Please Try Again Leter!");
}
}
This function returns all the rows which contain duplicate value in the LcNoListId column. But I don't need any duplicate values in LcNoListId column.
It is clearly shown that this Distinct() function is not working in this context. Please help me to find a solution.
Use the following query:
var query = objBTBPendingList
.Where(x => x.ContractListId == id && x.UdAmendList == null)
.GroupBy(c => c.LcNoListId)
.Select(grp => grp.First());
But looks like you have stuck with ineffective repository pattern realization. With pure EF Core it is possible to make more performant query and do not retrieve duplicates and not wanted records from database.

Retrieving data from database for comparison

I am able to retrieve items and its details from the database but what i want to do is, when i get an item, i compare its quantity to a certain number.
Controller
$item = Item::all();
if($item->quantity = 5)
{
return $response;
}
else
{
//
}
What is happening here is, it actually sets 5 to the item's quantity but instead i want to get the quantity of the item selected and compare if it is equal to 5. How do i do this?
You are assigning the value with a single '=' since it's an assignment operator.
Instead, compare the values with '=='
$item = Item::all();
if($item->quantity == 5)
{
return $response;
}
else
{
//
}

using group() breaks getSelectCountSql in magento

When I'm using
$collection->getSelect()->group('entity_id')
or
$collection->groupByAttribute('entity_id')
It breaks getSelectCountSql and I'm getting 1 record and 1 page.
Magento does
$countSelect->columns('COUNT(DISTINCT e.entity_id)');
Is there a way to fix it?
I run into it,While overriding _prepareCollection of Mage_Adminhtml_Block_Catalog_Product_Grid
Thanks
I updated the lib/Varien/Data/Collection/Db.php file to allow this as I had to have it work. You'll have to keep track of this for upgrades but it works.
public function getSelectCountSql()
{
$this->_renderFilters();
$countSelect = clone $this->getSelect();
$countSelect->reset(Zend_Db_Select::ORDER);
$countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
$countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
$countSelect->reset(Zend_Db_Select::COLUMNS);
// Count doesn't work with group by columns keep the group by
if(count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) {
$countSelect->reset(Zend_Db_Select::GROUP);
$countSelect->distinct(true);
$group = $this->getSelect()->getPart(Zend_Db_Select::GROUP);
$countSelect->columns("COUNT(DISTINCT ".implode(", ", $group).")");
} else {
$countSelect->columns('COUNT(*)');
}
return $countSelect;
}
in some cases, the method from Eric doesn't work.
It's better to rewrite the getSize() method to
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
$result = $this->getConnection()->fetchAll($sql, $this->_bindParams);;
foreach ($result as $row) {
$this->_totalRecords += reset($row);
}
}
return intval($this->_totalRecords);
}
I have solved this using the function below:
public function getSize()
{
return sizeof( $this->getAllIds());
}
This helped me in issue of getSize() returning 1 count of product collection in Magento CE 1.5.
I have overwritten the Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection file and place above function.
Very nice article
Here are few changes I made in order to make it work for me
Changes suggested in Db.php are not required for resolving group by in catalog collection.
I made the similar change in
Catalog->model->Ressource->EAV->Mysql4->product->collection.php
Here is the code I added to getSelectCountSql()
if(count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) { $countSelect->reset(Zend_Db_Select::GROUP); }
After this things get resolved but a new issue comes in .. In Layered navigation quantities for all the filters is 1.
I made it without touching Core files by overriding the getSize() method of my collection.
public function getSize()
{
if (count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) {
// Create a new collection from ids because we need a fresh select
$ids = $this->getAllIds();
$new_coll = Mage::getModel('module_key/model')->getCollection()
->addFieldToFilter('id', array('in' => $ids));
// return the collection size
return $new_coll->getSize();
}
return parent::getSize();
}
Tell me if that works for you..
Bouni

Linq2SQL "Local sequence cannot be used in LINQ to SQL" error

I have a piece of code which combines an in-memory list with some data held in a database. This works just fine in my unit tests (using a mocked Linq2SqlRepository which uses List).
public IRepository<OrderItem> orderItems { get; set; }
private List<OrderHeld> _releasedOrders = null;
private List<OrderHeld> releasedOrders
{
get
{
if (_releasedOrders == null)
{
_releasedOrders = new List<nOrderHeld>();
}
return _releasedOrders;
}
}
.....
public int GetReleasedCount(OrderItem orderItem)
{
int? total =
(
from item in orderItems.All
join releasedOrder in releasedOrders
on item.OrderID equals releasedOrder.OrderID
where item.ProductID == orderItem.ProductID
select new
{
item.Quantity,
}
).Sum(x => (int?)x.Quantity);
return total.HasValue ? total.Value : 0;
}
I am getting an error I don't really understand when I run it against a database.
Exception information:
Exception type: System.NotSupportedException
Exception message: Local sequence cannot be used in LINQ to SQL
implementation of query operators
except the Contains() operator.
What am I doing wrong?
I'm guessing it's to do with the fact that orderItems is on the database and releasedItems is in memory.
EDIT
I have changed my code based on the answers given (thanks all)
public int GetReleasedCount(OrderItem orderItem)
{
var releasedOrderIDs = releasedOrders.Select(x => x.OrderID);
int? total =
(
from item in orderItems.All
where releasedOrderIDs.Contains(item.OrderID)
&& item.ProductID == orderItem.ProductID
select new
{
item.Quantity,
}
).Sum(x => (int?)x.Quantity);
return total.HasValue ? total.Value : 0;
}
I'm guessing it's to do with the fact
that orderItems is on the database
and releasedItems is in memory.
You are correct, you can't join a table to a List using LINQ.
Take a look at this link:
http://flatlinerdoa.spaces.live.com/Blog/cns!17124D03A9A052B0!455.entry
He suggests using the Contains() method but you'll have to play around with it to see if it will work for your needs.
It looks like you need to formulate the db query first, because it can't create the correct SQL representation of the expression tree for objects that are in memory. It might be down to the join, so is it possible to get a value from the in-memory query that can be used as a simple primitive? For example using Contains() as the error suggests.
You unit tests work because your comparing a memory list to a memory list.
For memory list to database, you will either need to use the memoryVariable.Contains(...) or make the db call first and return a list(), so you can compare memory list to memory list as before. The 2nd option would return too much data, so your forced down the Contains() route.
public int GetReleasedCount(OrderItem orderItem)
{
int? total =
(
from item in orderItems.All
where item.ProductID == orderItem.ProductID
&& releasedOrders.Contains(item.OrderID)
select new
{
item.Quantity,
}
).Sum(x => (int?)x.Quantity);
return total.HasValue ? total.Value : 0;
}

linqToSql related table not delay loading properly. Not populating at all

I have a couple of tables with similar relationship structure to the standard Order, OrderLine tables.
When creating a data context, it gives the Order class an OrderLines property that should be populated with OrderLine objects for that particular Order object.
Sure, by default it will delay load the stuff in the OrderLine property but that should be fairly transparent right?
Ok, here is the problem I have: I'm getting an empty list when I go MyOrder.OrderLines but when I go myDataContext.OrderLines.Where(line => line.OrderId == 1) I get the right list.
public void B()
{
var dbContext = new Adis.CA.Repository.Database.CaDataContext(
"<connectionString>");
dbContext.Connection.Open();
dbContext.Transaction = dbContext.Connection.BeginTransaction();
try
{
//!!!Edit: Imortant to note that the order with orderID=1 already exists
//!!!in the database
//just add some new order lines to make sure there are some
var NewOrderLines = new List<OrderLines>()
{
new OrderLine() { OrderID=1, LineID=300 },
new OrderLine() { OrderID=1, LineID=301 },
new OrderLine() { OrderID=1, LineID=302 },
new OrderLine() { OrderID=1, LineID=303 }
};
dbContext.OrderLines.InsertAllOnSubmit(NewOrderLines);
dbContext.SubmitChanges();
//this will give me the 4 rows I just inserted
var orderLinesDirect = dbContext.OrderLines
.Where(orderLine => orderLine.OrderID == 1);
var order = dbContext.Orders.Where(order => order.OrderID == 1);
//this will be an empty list
var orderLinesThroughOrder = order.OrderLines;
}
catch (System.Data.SqlClient.SqlException e)
{
dbContext.Transaction.Rollback();
throw;
}
finally
{
dbContext.Transaction.Rollback();
dbContext.Dispose();
dbContext = null;
}
}
So as far as I can see, I'm not doing anything particularly strange but I would think that orderLinesDirect and orderLinesThroughOrder would give me the same result set.
Can anyone tell me why it doesn't?
You're just adding OrderLines; not any actual Orders. So the Where on dbContext.Orders returns an empty list.
How you can still find the property OrderLines on order I don't understand, so I may be goofing up here.
[Edit]
Could you update the example to show actual types, especially of the order variable? Imo, it shoud be an IQueryable<Order>, but it's strange that you can .OrderLines into that. Try adding a First() or FirstOrDefault() after the Where.

Resources