so I have this big table that I want to query and it's so slow, I got a tip that using select is more efficient than include. so how can I convert include to select, in this big query.
ProductEntity? i = await _context.Set<ProductEntity>()
.Include(i => i.Media)
.Include(i => i.Categories)
.Include(i => i.Locations)
.Include(i => i.Reports)
.Include(i => i.Comments)!.ThenInclude(x => x.LikeComments)
.Include(i => i.Bookmarks)
.Include(i => i.Votes)
.Include(i => i.User)!.ThenInclude(x => x.Media)
.Include(i => i.User)!.ThenInclude(x => x.Categories)
.Include(i => i.Forms)!.ThenInclude(x => x.FormField)
.Include(i => i.Teams)!.ThenInclude(x => x.User)!.ThenInclude(x => x.Media)
.Include(i => i.VoteFields)!.ThenInclude(x => x.Votes)
.AsNoTracking()
.FirstOrDefaultAsync(i => i.Id == id && i.DeletedAt == null);
return new GenericResponse<ProductEntity>(_mapper.Map<ProductEntity>(i));
and this is getById method, which just takes one row, I have a getAll that returns a list of products just like this.
The most performant code is always the code that does the least amount of work.
It's possible that what was meant by the 'tip' that "using select is more efficient" may have more to do with answering the question: "do you really, really, really need all that data to be returned?".
Consider, for every .Include you have, EF will be making it's own query to the database to return whatever records are linked by the foreign keys. It's actually pretty efficient on doing that either on the DB side, or in memory if it already has the connected records in memory. (depending on your caching configuration) However, it's going to return the entire Entity referenced. Which may be fine. But, what if each of those 11 sub-entities plus the 7 sub-sub-entities that you have connecting there are each rather large. Do you really, really, really need to return all of that data? Or could you return smaller objects using something like:
var mySmallerObject = await _context.Set<ProductEntity>()
.Include(i => i.Media)
.Include(i => i.Categories)
. . .
.Select(_ => new SomeMuchSmallerObject {
SomeFieldOnProduct = _.SomeFieldOnProduct,
TheOnlyThingINeedFromMedia = _.Media.TheOnlyThingINeedFromMedia,
TheOnlyCategoryFieldINeed = _.Categories.TheOnlyCategoryFieldINeed,
. . . // etc
})
UPDATED
Note: You will still need to either keep all those .Include()s to let EF implicitly build the joins, or else convert them to explicit .Join() statements. By making a smaller object that you use in the .Select() statement, EF will translate this request into a much more optimized query to the DB that only selects the few fields you actually need, and not even return any of the unwanted fields from the database. This also allows you to take full advantage of any indexes you have on the underlying tables in the DB.
Just a thought.
Related
All,
I have a query as such:
_AddOrderBy(sortOptions, query)
.Fetch(x => x.ImageType).Eager
.Fetch(x => x.User).Eager
.Fetch(x => x.Partner).Eager
.Inner.JoinAlias(x => x.Partner, () => p).Fetch(x => x.Company).Eager
.Skip(startIndex)
.Take(pageSize)
.List<ImageRequest>();
In the above QueryOver I call _AddOrderBy() method which adds an order by clause. The challenge I face is how do I create an "order by" that references a property (ordering by "CompanyName") that lies within the following association path without conflicting with my Fetch()/Inner joins:
ImageRequest.Partner.Company.CompanyName
Inside my _AddOrderBy() I have this:
Partner p = null;
Company comp = null;
order = query.Inner.JoinAlias(x => x.Partner, () => p)
.Inner.JoinAlias(x => x.Company, () => comp)
.OrderBy(x => comp.CompanyName);
But this gives me a run time exception stating that I have duplicate key (referring to Partner) in the criteria. I can see that this is conflicting with my eager fetching.
My questions is:
How do I add an "order by" so it works with my Fetching.
The beauty of using an Alias in QueryOver is that you don't have to use Fetch or JoinAlias in your _AddOrderBy() method again if the Join happens in the query already. You only need to declare the Alias with the same name.
Therefore your _AddOrderBy() can just look like this:
Partner p = null;
Company comp = null;
order = query
.Inner.JoinAlias(x => p.Company, () => comp) // you can use p here if it was used in the query before
.OrderBy(x => comp.CompanyName);
The reason this works is this: If you put the whole code into one method it will obviously work. Splitting it into two methods still works, because Partner p is not a reference to an object in memory but an Alias that is simply translated into a string for the SQL query.
Update
Here is a working example using redux-observable. https://redux-observable-playground-ykzsyp.stackblitz.io This achieves what I want using mergeMap and if/else statement, but I was hoping to use Observable.filter as that seems more elegant.
Original question
I have an epic that currently dispatches a single action but would like to dispatch different actions based on a filter using a single stream. Here is the current code:
const streamEpic = (action$) => action$.pipe(
ofType('START_PLAYBACK_STREAM'),
switchMap(playbackStream$),
filter((playEvent) => playEvent.type === 'LOAD')),
map((playEvent) => loadActionCreator(playEvent.fileName))
// how can I filter on other types?
// and dispatch other actions?
);
I've seen many rxjs examples that use a single stream and filter to map different actions, for example:
playbackStream$
.filter((playEvent) => playEvent.type === 'LOAD'))
.map((playEvent) => loadActionCreator(playEvent.fileName));
playbackStream$
.filter((playEvent) => playEvent.type === 'START'))
.map((playEvent) => startActionCreator());
playbackStream$
.filter((playEvent) => playEvent.type === 'STOP'))
.map((playEvent) => stopActionCreator());
I'm trying to do this same thing in redux-observable but no luck. If I use tap, ignoreElements, and store.dispatch I can get the following to work but I know its an anti-pattern.
const streamLoadEvents = (action$, store) => action$.pipe(
ofType('START_PLAYBACK_STREAM'),
tap(() => {
playbackStream$
.filter((playEvent) => playEvent.type === 'LOAD'))
.map((playEvent) => store.dispatch(loadActionCreator(playEvent.fileName)));
playbackStream$
.filter((playEvent) => playEvent.type === 'START'))
.map((playEvent) => store.dispatch(startActionCreator()));
playbackStream$
.filter((playEvent) => playEvent.type === 'STOP'))
.map((playEvent) => store.dispatch(stopActionCreator()));
}),
ignoreElements()
);
I know that I could also use a switch or if/else statement inside of something like map or switchMap, like the answer here: Redux-Observable multiple actions in single epic, but I'd like to avoid this as its rather inelegant and does not take full advantage of streaming operators. The answer here: https://stackoverflow.com/a/40895613/367766 seems to get me a little closer...
What's the suggested approach here? Are the operators or example you can point me to? Thanks!
You're right, if/else should only be used as a last resort and there are probably several ways you could approach this, in any case, here's my take on this:
There's a merge method which can be viewed as a reactive equivalent of the if/else operator: you provide it with observables, and if any of them emits, the resulting observable will emit it's own value(AC) as well. When a new action comes through, we inspect it, and pick a new action creator(AC) accordingly. Let's take look at some code:
const filteredAction$ = action$.pipe(
ofType('START_PLAYBACK_STREAM'),
);
Nothing interesting here, just filtering out the action types we're not interested in, and then
const operation$ = merge(
filteredAction$.pipe(
filter((action) => action.payload.type === 'LOAD'),
mapTo(loadActionCreator),
),
filteredAction$.pipe(
filter((action) => action.payload.type === 'START'),
mapTo(startActionCreator),
),
filteredAction$.pipe(
filter((action) => action.payload.type === 'STOP'),
mapTo(stopActionCreator),
),
).pipe(
startWith(startActionCreator)
);
Here we are choosing which action creator to use based on the action's payload (please note that I'm following the flux standard for actions - the action's data is under the payload property now, there's an awesome library you could use as a helper for it. Also, you should probably rename the 'type' prop to avoid confusion).
mapTo basically tells the operation$ stream what to emit, you can think of this expression as assigning a function to some variable for later use. Every time an epic gets invoked, we'll choose a proper action creator for it here.
startWith is actually not needed here (assuming the first action always includes
the 'START' type) and is for semantic purposes only.
Last but not least, an epic has to return at least one action for dispatching:
return combineLatest(
operation$,
filteredAction$
)
.pipe(
map((arg) => {
const operation = arg[0];
const actionObject = arg[1];
return operation(actionObject);
})
)
Latest values from both streams are combined together to form a follow up action: operation$ (which yields us a proper action creator function) and filteredAction$ (always contains the action itself, we might need some data from it).
In this link http://www.voip-info.org/wiki/index.php?page_id=1735
[settings]
<family name> => <driver>,<database name>~np~[~/np~,table_name~np~]~/np~
sippeers => mysql,asterisk,sip_peers
sipusers => mysql,asterisk,sip_users
queues => mysql,asterisk,queue_table
queue_members => mysql,asterisk,queue_member_table
meetme => mysql,asterisk,meetme_table
voicemail => mysql,asterisk^
Can't the family name by anything as we wish? Can I have sipfriends as a family name?
You can use ANY table for example like this
sippeers => mysql,asterisk,sipfriends
sipusers => mysql,asterisk,sipfriends
Where sipfriends can be table or view(peer update will not work unless you do ONUPDATE trigger).
If you want class enother name, for example something like this
sippeers => mysql,asterisk,sipfriends
sipusers => mysql,asterisk,sipfriends
sippeers2 => mysql,asterisk,sipfriends2
sipusers2 => mysql,asterisk,sipfriends2
then you need do changes in chan_sip.c to lookup both classes.
This is such a trivial problem that I can't believe I couldn't find an answer.
Symfony 2, doctrine 2.1. I've got two entities and one intermediate entity (join table). User, Pref, and UsersPrefs. Pref table is dictionary table, so that I could change pref name in one place only. Ok, let's see the picture:
infographic http://dl.dropbox.com/u/22495762/infographic.png
As You can see, I want to have a checkbox group, with all the possible choices (prefs) and preferred choices checked. So, if there are 3 prefs, and only 2 selected by the user, there should be 3 checkboxes, 2 selected.
It's simple, if done plain PHP - query database twice to get list of all prefs and user prefs, render checkboxes depending on values, add some actions to handle form submit, done.
But for the life of God I can't get this to work using symfony & doctrine. I was able to get to the point where I can update relationships in doctrine and further in database, but I'm using raw query values for that:
$data = $request->request->get('some_form');
and this supposedly isn't the way it should be done?
Morevoer, I'm completely stuck as to how should I display checkbox list. I either get list of all options, none checked, or only user options, all checked. Or 'left joined' result set with checkboxes for all cases, useless anyway.
I've come to the point where I tried to overload twig checkbox template, but I couldn't pass variables to the form template, and that was the last straw...
EDIT:
This way I'm getting group of checkboxes, not connected to user choices:
->add('prefs', 'entity', array(
'class' => 'Some\TestBundle\Entity\Pref',
'expanded' => 'true',
'multiple' => 'true',
'property' => 'name'
))
And this way I'm getting only user choices, all checked:
->add('prefs', 'entity', array(
'class' => 'Some\TestBundle\Entity\UserPrefs',
'multiple' => 'false',
'expanded' => 'false',
'property' => 'pref.name',
'query_builder' => function(EntityRepository $er) use ($id) {
return $er->createQueryBuilder('u')
->where("u.user = :id")
->setParameter('id', $id)
;
},
))
And I tried left joins and other options, but at best I could get list of all possible options for all possible users, checked accordingly.
EDIT (POSSIBLE SOLUTION):
I'm displaying checkbox group:
->add('pref_ids', 'choice', array(
'choices' => array(
'1' => 'pref one',
'2' => 'pref two',
'3' => 'pref three',
),
'expanded' => 'true',
'multiple' => 'true'
))
I've added $pref_ids array in User entity. Now I just need to set values in array according to preferences chosen by user:
public function setPrefIds()
{
$prefs = $this->getPrefs();
$this->pref_ids = array();
foreach($prefs as $pref){
array_push($this->pref_ids, $pref->getPref()->getId());
}
return $this;
}
This way I get appropriate checkboxes checked.
Writing values to database is reversal of the process. I'm getting input values from request:
$data = $request->request->get('edit_form');
var_dump($data['pref_ids']);
Removing all user prefs:
foreach ($userPrefs as $pref){
$em->remove($pref);
}
And setting actual associations in doctrine from ids:
$entity->setPrefsById($em, $data['pref_ids']);
Here I'm passing entity manager to entity itself, but I need to refactor it, because it looks kinda messy this way.
Then $em->flush(); and that's it.
That's the best I could come up with. Probably it's overcomplicated and should be done entirely different way. Unfortunately couldn't figure out this "other way".
You need the choice field type: http://symfony.com/doc/current/reference/forms/types/choice.html
In your builder, it will be something like
$builder->add('prefs', 'choice', array('multiple' => true, 'expanded' => true, 'choices' => fetch the available prefs from the database here);
Edit: Sorry I'm mistaken, you need the "Entity" type, which fetches automatically the choices from the database: http://symfony.com/doc/current/reference/forms/types/entity.html
You must still put multiple => true expanded => true to get checkboxes.
I have a query in CakePHPthat has a stored "datetime" field called DropIn.drop_in_time. I would like to only "find" entries where the DropIn.drop_in_time is > NOW() but am having trouble getting it to do that.
The condition DropIn.drop_in_time >' => 'NOW() didn't get the right results in the query below. Is there a better way to do it?
$requests = $this->DropIn->find('all', array(
'conditions' => array('DropIn.drop_in_time >' => 'NOW()', 'or' => array(array('DropIn.user_id' => $this->Auth->user('id')), array('DropIn.id' => $drop_in_ids))),
'order'=>array('DropIn.created'=>'DESC')));
If you separate the value as 'DropIn.drop_in_time' => 'NOW()', 'NOW()' is taken to mean the literal value string "NOW()". Just write it as one SQL fragment instead: 'DropIn.drop_in_time > NOW()'. Alternatively, use 'DropIn.drop_in_time >' => date('Y-m-d H:i:s').
If you really want to put DB expressions into CakePHP finds, you can use the expression method:
'DropIn.drop_in_time.' => $db->expression('CURDATE()');
However this is kinda of losing the point of the database abstraction that a framework provides, so do as suggested by deceze and compare it with date('Y-m-d H:i:s')
use DboSource::expression('NOW') instead of only NOW()