Filtering navigation property in eager loading - entity-framework-5

I have been working with soft delete and now i want to load the navigation properties of my entity that are not "deleted". I have found a way, my problem this way is not to clear for me, there is another way to do this.
Context.CreateSet().Include("Salary").Select(u => new {User= u, Salary = u.Salarys.Where(s => !s.Deleted)}).AsQueryable().Select(a => a.User).AsQueryable();

Eager loading doesn't support filtering. Your code can be simplified to:
var users = Context.CreateSet<User>()
.Select(u => new {
User = u,
Salary = u.Salaries.Where(s => !s.Deleted)
})
.AsEnumerable()
.Select(a => a.User);
Include is not needed because you are replacing it with your own query and AsQueryable is not needed because the query is IQueryable all the time till called AsEnumerable which will sqitch to Linq-to-Objects when selecting users and selected salaries. EF will take care of correctly fixing navigation properties for you.

Related

CS1646 Keyword, identifier, or string expected after verbatim specifier: #

tables in my EntityFramework model are events, eventtypes, subevents, subeventtypes
using the MVC5 builders (right click on controllers, add, add controller) I created controllers and views for the last three tables without issue however when I create the controller and views for the events entity I produce the following errors
Keyword, identifier, or string expected after verbatim specifier: #
'EventType' is a type, which is not valid in the given context
the code that was generated in the event controller is
{
private Entities db = new Entities();
// GET: Events
public ActionResult Index()
{
var events = db.Events.Include(# => #.EventType); ERROR HERE
return View(events.ToList());
}
any help with this issue would be greatly appreciated
TIA
I experienced the same issue when using the "MVC Controller with views, using Entity Framework" template.
var #group = await _context.Groups
.Include(# => #.Company)
.FirstOrDefaultAsync(m => m.GroupId == id);
My workaround was simple to replace the # symbol with another character i.e. g
var #group = await _context.Groups
.Include(g => g.Company)
.FirstOrDefaultAsync(m => m.GroupId == id);

How can I eager fetch content of custom types in a ContentManager query?

I'm running into some n+1 performance issues when iterating over a collection of ContentItems of a custom Type that I created solely through migrations.
ContentDefinitionManager.AlterPartDefinition("MyType", part => part
.WithField("MyField", field => field
...
)
);
ContentDefinitionManager.AlterTypeDefinition("MyType", type => type
.WithPart("MyType")
);
Every time I access a field of this part a new query is performed. I can use QueryHints to avoid this for the predefined parts
var myItems = _orchardServices.ContentManager.Query().ForType("MyType")
.WithQueryHints(new QueryHints().ExpandParts<LocalizationPart()
...
);
but can I do this for the ContentPart of my custom type too? This does not seem to work:
var myItems = _orchardServices.ContentManager.Query().ForType("MyType")
.WithQueryHints(new QueryHints().ExpandParts<ContentPart>()
...
);
How can I tell Orchard to just get everything in one go? I'd prefer to be able to do this without writing my own HQL or directly addressing the repositories.
Example:
var myItems = _orchardServices.ContentManager.Query().ForType("MyType");
#foreach(var item in myItems.Take(100)) {
foreach(var term in item.Content.MyItem.MyTaxonomyField.Terms) {
// Executes 100 queries
<div>#term.Name</div>
}
}
TaxonomyField doesn't store ids and using the TaxonomyService inside of the loop wouldn't improve performance. Right now, to work around this, I fetch all TermContentItems.Where(x => myItems.Select(i => i.Id).Contains(TermPartRecord.Id)) from the repository outside of the loop as well as a list of all the terms of the Taxonomy that the field is using. Then inside the loop:
var allTermsInThisField = termContentItems.Where(tci => tci.TermsPartRecord.Id == c.Id)
.Select(tci => terms.Where(t => t.Id == tci.TermRecord.Id).Single()).ToList()
I'm not a very experienced programmer but this was the only way I could see how to do this without digging into HQL and it seems overly complicated for my purposes. Can Orchard do this in less steps?

Post to SMF Forum via PHP

I am building a CMS that supports a website which also contains an SMF forum (2.0.11). One of the modules in the CMS involves a "report" that tracks attendance. That data is queried to tables outside of smf, but in the same database. In addition to what it does now, I would also like for a post to be made in a specific board on the SMF forum containing the formatted content. As all of the posts are contained by the database, surely this is possible, but it seems there is more to it than a single row in a table.
To put it in the simplest code possible, below is what I want to happen when I click Submit on my page.
$title = "2015-03-04 - Attendance";
$author = "KGrimes";
$body = "Attendance was good.";
$SQL = "INSERT INTO smf_some_table (title, author, body) VALUES ($title, $author, $body)";
$result = mysqli_query($db_handle, $SQL);
Having dug through the smf DB tables and the post() and post2() functions, it seems there is more than one table involved when a post is made. Has anyone outlined this before?
I've looked into solutions such as the Custom Form Mod, but these forms and templates are not what I am looking for. I already have the data inputted and POST'ed to variables, I just need the right table(s) to INSERT it into so that it appears on the forum.
Thank you in advance for any help!
Source: http://www.simplemachines.org/community/index.php?topic=542521.0
Code where you want to create post:
//Define variables
//msgOptions
$smf_subject = "Test Title";
//Handle & escape
$smf_subject = htmlspecialchars($smf_subject);
$smf_subject = quote_smart($smf_subject, $db_handle);
$smf_body = "This is a test.";
//Handle & escape
$smf_body = htmlspecialchars($smf_body);
$smf_body = quote_smart($smf_body, $db_handle);
//topicOptions
$smf_board = 54; //Any board id, found in URL
//posterOptions
$smf_id = 6; //any id, this is found as ID in memberlist
//SMF Post function
require_once('../../forums/SSI.php');
require_once('../../forums/Sources/Subs-Post.php');
//createPost($msgOptions, $topicOptions, $posterOptions);
// Create a post, either as new topic (id_topic = 0) or in an existing one.
// The input parameters of this function assume:
// - Strings have been escaped.
// - Integers have been cast to integer.
// - Mandatory parameters are set.
// Collect all parameters for the creation or modification of a post.
$msgOptions = array(
'subject' => $smf_subject,
'body' => $smf_body,
//'smileys_enabled' => !isset($_POST['ns']),
);
$topicOptions = array(
//'id' => empty($topic) ? 0 : $topic,
'board' => $smf_board,
'mark_as_read' => true,
);
$posterOptions = array(
'id' => $smf_id,
);
//Execute SMF post
createPost($msgOptions, $topicOptions, $posterOptions);
This will create the simplest of posts with title and body defined by you, along with location and who the author is. More parameters can be found in the SMF functions database for createPost. The SSI and Subs-Post.php includes must be the original directly, copying them over doesn't do the trick.

Kohana/ORM - Assign relations to views

I have an object in a controller's method:
$post = ORM::factory('post', array('slug' => $slug);
that is sent to the view:
$this->template->content = View::factory('view')->bind('post', $post);
I've created 1-n relation between post and comments. So good so far.
The main issue is: how should I pass post comments to the view? Currently I'm getting them in the view ($post->comments->find_all()) but I don't feel it's the best method (and not matching MVC standards in my humble opinion). I was also thinking about assigning them to the property in the controller ($post->comments) however I get an error about undefined property (which makes sense to me).
How would you recommend to solve that issue?
Why not grab the comments in the controller and pass them to the view for presentation? At least that's how I'd go about this.
$post = ORM::factory('post', array('slug' => $slug));
$comments = $post->comments->find_all();
$this->template->content = View::factory('view')->bind('comments', $comments);
In regards to your multiple pages comment, which I assume you mean posts...
This is what I would usually do.
$posts = ORM::factory('post', array('slug' => $slug))->find_all();
$view = new View('view');
foreach ($posts as $post) {
$view->comments = $post->comments;
$this->template->content .= $view->render();
}
Though this may not be the most resource friendly way to accomplish this, especially if you're working with many posts. So passing the posts to the view and then doing the foreach loop inside the view may be a better way to go about this.
$posts = ORM::factory('post', array('slug' => $slug))->find_all();
$this->template->content = View::factory('view')->bind('posts', $posts);
Though I also don't necessarily think running a select query from the view is the worst thing in the world. Though I'm no expert... ;)
I had asked this question a while ago in regards to CodeIgniter... passing an Array to the view and looping through it seemed to be the favored response...
Using CodeIgniter is it bad practice to load a view in a loop

Magento - get filterable attributes by category

I have created a custom navigation module specifically for a website, but I really want to be able to list filterable attributes by a specific category. So for instance my main navigation is:
Category 1
Category 2
Category 3 etc.
I then that when a user mouses over a category, they are then presented with an expanded menu with a few filterable options e.g.:
Category 1
View by manufacturer:
Manufacturer 1
Manufacturer 2
Manufacturer 3 etc.
I am able to get all filterable attributes for the store, but I want this list to pull in only the filterable attributes per category, as for instance Category 1 may have different manufacturers to Category 2. I then need to cache these results as this will not change often.
The answer that Joe gave was a good starting point, but the attributes didn't returned any options yet. After a lot of frustrations I solved the problem with the following code. Hope it helps all of you out.
$layer = Mage::getModel("catalog/layer");
foreach($categories as $categoryid) {
$category = Mage::getModel("catalog/category")->load($categoryid);
$layer->setCurrentCategory($category);
$attributes = $layer->getFilterableAttributes();
foreach ($attributes as $attribute) {
if ($attribute->getAttributeCode() == 'price') {
$filterBlockName = 'catalog/layer_filter_price';
} elseif ($attribute->getBackendType() == 'decimal') {
$filterBlockName = 'catalog/layer_filter_decimal';
} else {
$filterBlockName = 'catalog/layer_filter_attribute';
}
$result = $this->getLayout()->createBlock($filterBlockName)->setLayer($layer)->setAttributeModel($attribute)->init();
foreach($result->getItems() as $option) {
echo $option->getLabel().'<br/>';
echo $option->getValue();
}
}
The only thing you'll need to do yourself is create the correct link using the getValue() functions.
This code has been tested in Magento 1.5
Magento uses the model Catalog_Model_Layer to accomplish this, so I'm guessing this may be your best bet. Caveat emptor, I have not tested this code yet:
$layer = Mage::getModel("catalog/layer");
foreach($categories as $categoryid) {
$category = Mage::getModel("catalog/category")->load($categoryid);
$layer->setCurrentCategory($category);
$attributes = $layer->getFilterableAttributes();
// do something with your attributes
}
Each iteration here will give you an object of the class Mage_Catalog_Model_Resource_Eav_Mysql4_Attribute_Collection, which you should be able to iterate over in a foreach loop to get your desired output.
For caching, try enabling block caching on your site and give the block a cache tag like the following. Magento will cache the HTML output and all will be right with the world:
protected function _construct() {
$this->addData(array(
'cache_lifetime' => 3600,
'cache_tags' => array(Mage_Catalog_Model_Product::CACHE_TAG),
'cache_key' => $someUniqueIdentifierYouCreate,
));
}
The cache will only be valid for the key you pass, so make sure that, if the menu is to change (w/o flushing the cache, for instance), that the cache key is different.
Hope that helps!
Thanks,
Joe

Resources