EF4 slow association access - asp.net

I'm building an ASP.NET 4 web application using EF4 and I have tables like this:
Product
Attribute
Product_Attribute_Map
Product_Attribute_Map is a cross table, many to many. So Product can have zero or many Attribute and vice versa.
In code I do this:
//Attribute a = new Attribute(); // Edit:
Attribute a = (from a in context.Attributes where a.AttributeID = 1 select a).First();
a.Name = "test";
Product.Attributes.Add(a);
I noticed a problem which makes this very slow. EF4 will execute this SQL on the server:
SELECT
[Extent2].* FROM [dbo].[Product_Attribute_Map] AS [Extent1]
INNER JOIN [dbo].[Product] AS [Extent2] ON [Extent1].[ProductID] = [Extent2].[ProductID]
WHERE [Extent1].[AttributeID] = #p1
I don't understand why it does this. An Attribute may be assigned to 10.000 Products, which makes this a bad query. It takes over 5 seconds to add an Attribute to a Product...
How can I prevent EF4 from selecting all attributes? And just select the attributes for this product.
Thanks
Edit: This is only using POCO t4 template. EntityObject template doesnt have this problem.

My guess: This happens because of LazyLoading used together with FixUpCollections generated by POCO template. When you add attribute to product, fixup collection will perform reverse operation as well - it will add prduct to attribute but first access to products collection in attribute will trigger lazy loading and so your query is executed. I don't like fixup collections ... You can modify POCO template to not use them or you can delete Products navigation property in Attribute (if you don't need it).

Related

Vaadin 7 - retrieve Beanitem from Grid Editor CommitEvent

I am (still) working with Vaadin 7.6.4 and im trying to write my own custom FieldGroup.CommitHandler
I am trying to retrieve the currently added item (grid row) from the the commitEvent itself.
While debugging I can see that all the Data is available in a property called itemId if I use the following trainwreck: commitEvent.getFieldBinder().getItemDataSource() inside the Debug-Inspector, however it is private.
The itemId is the exact bean-entity i want to access. I only managed to access single fields of the entity with the following trainwreck: commitEvent.getFieldBinder().getField(propertyId).getValue(). However this is cumbersome and does not give me the entity as a whole (and to be precise does not retrieve the information from the entity, but rather from the displaying elements of the grid).
Is there a way to access the currently edited entity (which is the datasource for the edited grid row), without declaring the entire grid as a global field and call the grid.getSelected()-method?
Also, is there a data-wise difference between post- and preCommit?
Since you are apparently using BeanItemContainer based on your comment of itemId, You could try something like the following:
BeanItem item = (BeanItem) commitEvent.getFieldBinder().getItemDataSource();
MyBean bean = (MyBean) item.getBean();
getBean() in this case returns itemId.

Create a record on DirPartyTable from code?

I have to create a new record on DirPartyTable .
I used this code:
DirPartyTable _myDirPartyTable;
myPartyNumber = DirPartyTable::getNewPartyNumber((webSession() == null));
myDirPartyTable = DirPartyTable::createNew(myPartyType , myName, myPartyNumber);
// or without partynumber
myDirPartyTable = DirPartyTable::createNew(myPartyType , myName);
But in both cases the standard method generate two Sequence ParyNumber.
In Debu mode I saw the system get two times the PartyNumber .
How can I create a record without creating holes in the sequence numeric?
I tried to use this another code:
select forupdate myDirPartyTable;
myDirPartyTable.name = ....;
//etc
myDirPartyTable.insert();
But does not create the record.
Thanks,
enjoy!
DirPartytable is the basis table of address book framework and is the top level of table inheritance hierarchy see references in Implementing the Global Address Book Framework (White paper)
You shouldn't try to directly create a party but create from your entity which implement the DirParty framework. When you create a vendor, you don't create a DirParty (with herited tables) and then create a VendTable and link them all together. Creating a vendor will do it directly.
Then, if you still encounter two times Party number calls, log a case at Microsoft support.
ulisses: I solved problem, I have to create before the PartyType (Organization or Person etc...)and after update my created DirPartyTable.
Just try the AxDirPartyTable Class like:
AxDirPartyTable axDirPartyTable;
axDirPartyTable = AxDirPartyTable::construct();
axDirPartyTable.parmName(myName);
axDirPartyTable.parmPartyNumber(myPartyNumber);
axDirPartyTable.save();
Examples could be found here: How to create a record in Global address book throgh code.

Drupal 7 - Using Views Relationships With Filters

In Views, I have an exposed filter that looks at the UID (User ID / Author), but is there a way to limit this to "ONLY" the users who have posted in this content type?
I tried adding a "Content: Author" relationship and hit Apply. I'm not exactly sure why, but it wasn't until this point that I could go back into the relationships and see MORE options, like: "User: Content authored" (which must then be dependent on the first relationship?) so I selected that one too and set it up like so:
Now I was able to go to the exposed filter and select the relationship:
But this didn't work-- the exposed filter continues to show all the registered users.
I also tried putting in a User Reference field (to this content type) and attaching that to a relationship, but it didn't allow anything to show and gave this SQL warning:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'field_data_field_hidden_name.uid' in 'on clause'
How can I limit this author exposed filter to "ONLY" the users who have posted in this content type?
There are a few drupal modules that may help you out. Such as Corresponding node references
However, if you are good with php code, you can create the logic to query the database and return the desired results (which would be the columns of the table). Create a contextual filter, then select a field (any field should work, but best select something in either content type). Then edit it, WHEN THE FILTER VALUE IS NOT AVAILABLE -> Provide default value -> PHP Code
$nid = arg(1);// current node id
$query = "SELECT <desired_field_column_name> FROM {<field_data_table_name>} c
WHERE c.<column_that_is_same_as_nid> = :nid";
$result = db_query($query, array(':nid' =>$nid));
$id = array();
while ($row = $result->fetch())
{
array_push($id, $row->field_curator_target_id);//put each node id that's referenced in array
}
$separated = implode("+", $id); // separate them by + for AND , for OR
return $separated; //eg.32 + 30 would represent nodes that you want.
In Linked theme there is answer about Views Selective Filters (aka "Views Selective Exposed Filters", aka views_filters_selective, aka views_selective_filters).
This module adds filters that have suffix "(selective)" in their names – add one you need instead of filter w/o the suffix.

After join, cannot filter by attribute qty - getting products from inventory that are in stock

You have been so helpful in the past that I keep coming back searching for help and learning.
This time I am trying to get all products that have a quantity greater than 1 and that are in stock (is_in_stock = 1)
$products = Mage::getModel('catalog/product')->getCollection();
//$products->addAttributeToSelect('*');
//SELECT `e`.*, `stock`.`qty` FROM `catalog_product_entity` AS `e` LEFT JOIN `cataloginventory_stock_item` AS `stock` ON stock.product_id = e.entity_id
$products->getSelect()->joinLeft(
array('stock'=>'cataloginventory_stock_item'),
'stock.product_id = e.entity_id',
array('stock.qty', 'stock.is_in_stock')
);
This returns qty and is_in_stock columns attached to the products table. You can test it as follows:
$products->getFirstItem()->getQty();
$products->getFirstItem()->getIsInStock();
The issue begins when I try to filter by qty and is_in_stock.
$products->addFieldToFilter(array(
array('Qty','gt'=>'0'),
array('Is_in_stock','eq'=>'1'),
));
This returns - Invalid attribute name never performing filtering. I am guessing it is trying search for e.qty but cannot find it.
So, I tried to filter differently:
$products->getSelect()->where("`qty` > 0");
$products->getSelect()->where("`is_in_stock` = 1");
This is not filtering as well even though, if you look at its sql query, (var_dump((string) $products->getSelect())), and run that query in phpMyAdmin, it works.
Alan Storm in his tutorial mentions that 'The database query will not be made until you attempt to access an item in the Collection'. So, I make the $products->getFirstItem() call but it still not executing the query or filtering in another words.
What am I doing wrong? Any ideas how to filter by attributes that are joined to the table?
Thank you again,
Margots
I would suggest that you try using $products->addAttributeToFilter... instead of $products->addFieldToFilter... - the addField method only works when the field is on the main table that you are querying (in this case catalog_product_entity). Because the inventory fields are in a joined table, you need to use addAttribute.
Hope this helps,
JD
After looking under the hood I learned that _selectAttributes instance field was not assigned in Mage_Eav_Model_Entity_Collection_Abstract class and that is why get exception. A solution usually would be what Jonathan Day suggested above - add addAttributeToFilter() method, however. It will return error since it cannot find such attribute for catalog/product. (qty and in_invetory are in cataloginventory_stock_item). I found two solutions to my problem both required going different direction:
One involved pursuing a way to query the Select statement that I had set for product collection(see above) but somehow it was not resetting the collection with new product. WhenI copied that Sql statment in phpMyAdmin, it worked, so how to query that statement from product collection:
$stmt = $products->getConnection('core_write')->query($products->getSelect()->__toString());
while($rows = $stmt->fetch(PDO::FETCH_ASSOC)){
echo "<br>Product Id ".$rows['entity_id'];
}
Instead of using catalog/product entity table I used the flat table - cataloginventory_stock_item to accomplish the same thing
$stockItem = new Mage_CatalogInventory_Model_Stock_Item();
$stockItems->addQtyFilter('>',0);
$stockItems->addFieldToFilter('is_in_stock',array('eq'=>'1'));
Now there is a collection of all products with qty > 0 and that are in stock.

Entity Framework throws SqlDate exception on the *lookup* table

I am using Entity Framework with asp.net mvc, but I don't think mvc plays a big role here.
I have an object Customer, and a lookup table (there are several, and they all behave the same way; so for simplicity I'll pick Territory). Both Customer and Territory have LastUpdated field (Datetime that is set manually in the code).
If I hardcode Territory, and get only Customer data from the View, I don't have any problems:
public ActionResult CreateCustomer([Bind(Exclude = "CustId")] Customer cm) {
cm.Territory = (from t in repo.Territory where t.ID == 2 select t).First();
repo.AddToCustomer(cm);
repo.SaveChanges();
}
As I said, no problems. However, if I use a dropdown in the view with the matching id (Territory.ID) - there is a problem. I have the following line in controller:
ViewData["territory"] = new SelectList(repo.Territory, "ID", "Name", 1);
and corresponding line in the View:
Territory: <%= Html.DropDownList("Territory.ID", (IEnumerable<SelectListItem>)ViewData["territory"])%>
I get good news and bad news: the good news is that I get the territory ID nicely assigned to the appropriate member of Customer object. The bad news is that Territory.LastUpdated value is set to 1/01/0001. Obviously, I don't care about this value - but it looks like EF cares. When I call SaveChanges I am getting the following error:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM
Looks like EF is trying to retrieve the value from the database, and then compare it with EF value... or maybe something else - but the bottom line is I can't figure out how to prevent it from trying to be so smart.
For now, I name DropDown ID to be something different ("terID" instead of "Territory.ID"), and using FormCollection:
int terID = Int32.Parse(formData["terID"]);
cm.Territory = (from d in repo.Territory
where d.ID == terID select d).First();
This works (which makes me comfortable with my analysis) but this cannot be the best way.
I also can't believe that nobody bumped into such problem - but I couldn't find anything relevant... The best I could find is link text but it's more of a hint without much details
I tried to cut out all unrelated stuff from the code - so if there are some typos, they are in the post; not necessarily in the code itself!
Thanks
Territory.LastUpdated is being set to the default value, as EF saves the whole row / what has changed you get an exception.
The easy way to fix this is to set it to DateTime.Now before saving.
I'm assuming you are using EF 1.0 which is not good at direct foreign key maping.
Territory posted from view to action is not bound to Datacontext, hence when you save your customer object - EF saves attached Territory Object as well.
You have to get Territory object from db first and then assign it to customer.
And Your solution is perfectly fine, cos there is no other for EF 1.0 )-:

Resources