Specified method is not supported MySql Entity Framwork 6 - mysql

I am trying to run the following Linq query from MySQL client
query = query.Where(c => c.CustomerRoles
.Select(cr => cr.Id)
.Intersect(customerRoleIds)
.Any()
);
This code looks okay, but gives the error:
System.NotSupportedException: Specified method is not supported.at MySql.Data.Entity.SqlGenerator.Visit(DbIntersectExpression expression)
This looks to me like an issue with .Intersect. Can anybody tell me the cause of this error and how to fix it?

i think #GertArnold's post is a correct and best of the answers, but i'm wonder why have you gotten NotSupportedException yet ? so the problem should not be from intersect probably.
where is customerRoleIds come from ? is it IQueryable<T> ?
break the query, and complete it step by step.
if you don't get exception at this lines:
var a = query.Select(c => new {
c,
CustomerRoleIDList = c.CustomerRoles.Select(cr => cr.Id).AsEnumerable()
})
.ToList();
var b = customerRoleIds.ToList();
you must get the result by this:
var b = query.Where(c => c.CustomerRoles.any(u => customerRoleIds.Contains(u.Id)))
.ToList();
if you get exception by above query, you can try this final solution to fetch data first, but note by this, all data will be fetched in memory first:
var a = query.Select(c => new {
c,
CustomerRoleIDList = c.CustomerRoles.Select(cr => cr.Id).AsEnumerable()
})
.ToList();
var b = a.Where(c => c.CustomerRoleIDList.any(u => customerRoleIds.Contains(u)))
.Select(u => u.c)
.ToList();

Using Intersect or Except is probably always troublesome with LINQ to a SQL backend. With Sql Server they may produce horrible SQL queries.
Usually there is support for Contains because that easily translates to a SQL IN statement. Your query can be rewritten as
query = query.Where(c => c.CustomerRoles
.Any(cr => customerRoleIds.Contains(cr.Id)));
I don't think that customerRoleIds will contain many items (typically there won't be hundreds of roles), otherwise you should take care not to hit the maximum number of items allowed in an IN statement.

query.Where(c => c.CustomerRoles
.Any(v=>customerRoleIds.Any(e=>e == v.Id))
.Select(cr => cr.Id))
.ToList();

Try adding toList() before intersect, that should enumerate results locally instead running on MySql, you will get performance hit thought.
query = query.Where(c => c.CustomerRoles.Select(cr => cr.Id)).ToList().Intersect(customerRoleIds);

Related

Laravel returns error max prepared statements after getting many count()'s

I am getting the following error from Laravel.
SQLSTATE[42000]: Syntax error or access violation: 1461 Can't create
more than max_prepared_stmt_count statements (current value: 16382)
(SQL: select count(*) as aggregate from guild)
I have tried removing the guild count statement, but this makes the next SQL query give an error.
$users = User::count();
$crowdfunding = CrowdfundingSettings::find(1);
$guilds = Guild::count();
$data = [
'totalItems' => ItemTemplate::totalCustomItems(),
'totalAbilities' => Ability::totalCustom(),
'totalMobs' => MobTemplate::all()->count(),
'totalQuests' => Quest::all()->count(),
'totalLootTables' => LootTable::all()->count(),
'totalMerchantTables' => MerchantTable::all()->count(),
'totalDialogue' => Dialogue::all()->count(),
'totalCraftingRecipes' => CraftingRecipe::all()->count(),
'totalItemSets' => ItemSetProfile::all()->count(),
'totalSkills' => Skill::totalCustom()
];
return response()->json([
'crowdfunding_settings' => $crowdfunding,
'accounts' => $users,
//'guilds' => $guilds,
'data' => $data,
]);
I am expecting results to from the statement, yet I get an error. I have increased max prepared statements to 32k, but I still get this error displaying it is set to 16k.
As Dimitri mentioned (and also confirmed here) you should not use ->all() when you only need the count and not the data in the model itself.
Replace $data like so:
$data = [
'totalItems' => ItemTemplate::totalCustomItems(),
'totalAbilities' => Ability::totalCustom(),
'totalMobs' => MobTemplate::count(),
'totalQuests' => Quest::count(),
'totalLootTables' => LootTable::count(),
'totalMerchantTables' => MerchantTable::count(),
'totalDialogue' => Dialogue::count(),
'totalCraftingRecipes' => CraftingRecipe::count(),
'totalItemSets' => ItemSetProfile::count(),
'totalSkills' => Skill::totalCustom()
];
Counting the amount of mob templates using MobTemplate::all()->count() will result in the following sql SELECT * FROM mob_template;. The results of that will be loaded into a Eloquent collection, that collection will then count the items it contains in PHP. This is very slow, memory heavy and as it turns out you might also run into issues with prepared statements.
Count the amount of mob templates using MobTemplate::count() will result in the following sql SELECT COUNT(*) FROM mob_template;. This means the database does all the heavy lifting for counting the records and it only returns the result. That way eloquent does not have to load a collection with a bunch of data and it does not have to count all its items in PHP.
Make sure you're disposing PreparedQuery or any other prepared SQL Command after execution. Disposing calls ClosePreparedStatement.

Delete multiple rows in YII2

I have an array of objects fetched from database:
$masterListContacts = MasterListContacts::find()
->select('master_list_contacts.*')
->innerJoin('master_contacts', '`master_contacts`.`id` = `master_list_contacts`.`master_contact_id`')
->with('masterContact')
->where(['user_id' => \Yii::$app->user->identity->id, 'slug' => $slug])
->all();
Under certain circumstances, I need to delete all rows from the database represented in this array. But with both delete() and deleteAll() methods I got an error Call to a member function ... on array. Could someone tell me please which one is the best way to accomplish this?
UPDATE:
Here is my database structure.
Found better solution:
\Yii::$app
->db
->createCommand()
->delete('master_contacts', ['id' => $deletableMasterContacts])
->execute();
Where $deletableMasterContacts is array of master_contacts ids, which should be deleted
You can painlessly remove ->select('master_list_contacts.*').
->innerJoin('master_contacts', '`master_contacts`.`id` = `master_list_contacts`.`master_contact_id`')
performs the same work that ->joinWith('masterContact').
For delete entites try use this code:
MasterListContacts::deleteAll(['user_id' => \Yii::$app->user->identity->id, 'slug' => $slug]);

EF4.1 Eager loaded linked objects are returned null

Can anyone explain why a Company is returned but Company.CompanyServices is null (even though I've created one in the test)?
public List<Company> GetContactCompanies(int contactId)
{
var query = (
from directorCompany in ctx.CompanyDirectors
.Where(d => d.ContactAddress.Contact.Id == contactId)
.Include(d => d.Company.CompanyServices)
select directorCompany.Company
).OrderBy(c => c.CompanyName).Distinct();
return query.ToList();
}
Note substituting the Include for .Include("Company.CompanyServices") has no effect
Is the Company.CompanyServices property marked as virtual? Check out ScottGu's blog on entity framework, where he creates POCO classes with one to many relationships he marks the collection properties as virtual.
When I first started using EF 4, that had me stumped for quite a while.
Obviously I can't see your entity classes so this may be a moot point!
Found an answer that's not wholly inuitive, but it works which is the main thing.
Happy to see one that plays on the original query...
var query = (
from directorCompany in ctx.CompanyDirectors
.Where(d => d.ContactAddress.Contact.Id == contactId)
select directorCompany.Company
).OrderBy(c => c.CompanyName).Distinct();
return query.Include(c => c.CompanyServices).ToList();

Help building up LINQ query when using anonymous types

I've started out with:
IQueryable<Author> authors2 = db.Authors;
Then I build up authors2 in multiple if statements, here's one of them
authors2 = authors2.Where(t => t.ItemAuthors.Any(b => b.Item.CategoryItems.Any(z => z.categoryID == int.Parse(ddlCategory.SelectedValue))));
Then finally I would like to append this to the end of the built up where clauses
authors2.OrderBy(x => x.text).Select(x => new
{
authorText = string.Format("{0} ({1})",x.text, x.ItemAuthors.Count())
});
To bind a control like this:
ddlAuthor.DataSource = authors2;
ddlAuthor.DataTextField = "authorText";
ddlAuthor.DataBind();
Apparently the compiler is not very happy about my select new statement. How can I rewrite this to achieve the same goal? I believe this is called creating an anonymous type.
It says an explicit conversion exists(are you missing a cast?) I can't figure out how to cast it.
In your third statement, the returned type is not same as authors2 because the Select projects a different type other than Author
So assign the value to a new variable
var authorsFinal = authors2
.OrderBy(x => x.text)
.Select(x => new
{
authorText = string.Format("{0} ({1})",
x.text,
x.ItemAuthors.Count())
});

How can I get FOUND_ROW()s from an active record object in rails?

When querying the database with:
#robots = Robot.all(:condition => [:a => 'b'], :limit => 50, :offset => 0)
What is the best way to get the total number of rows without the :limit?
In raw MySQL you could do something like this:
SELECT SQL_CALC_FOUND_ROWS * FROM robots WHERE a=b LIMIT 0, 50
SELECT FOUND_ROWS();
Is there an active record way of doing this?
This works for me:
ps = Post.all(:limit => 10, :select => "SQL_CALC_FOUND_ROWS *")
Post.connection.execute("select found_rows()").fetch_hash
=> {"found_rows()"=>"2447"}
This will probably not work for joins or anything complex, but it works for the simple case.
Robot.count actually is the solution you want.
Reading one of the comments above, it looks like you may have a misunderstanding of how .count works. It returns a count of all the rows in the table only if there's no parameters.
but if you pass in the same conditions that you pass to all/find eg:
Robot.count(:conditions => {:a => 'b'})
.count() will return the number of rows that match the given conditions.
Just to be obvious - you can even save the condition-hash as a variable to pass into both - to reduce duplication, so:
conds = {:a => 'b'}
#robots = Robot.all(:conditions => conds, :limit => 50)
#num_robots = Robot.count(:conditions => conds)
That being said - you can't do an after-the-fact count on the result-set (like in your example). ie you can't just run your query then ask it how many rows would have been found. You do actually have to call .count on purpose.
search = Robot.all(:condition => ["a=b"], :offset => 0)
#robots = search[0..49]
#count = search.count
That should get what you want, gets all the Robots for counting and then sets #robots to the first 50. Might be a bit expensive on the resource front if the Robots table is huge.
You can of course do:
#count=Robot.all(:condition => ["a=b"], :offset => 0).count
#robots=Robot.all(:condition => ["a=b"], :limit => 50, :offset => 0)
but that will hit the database twice on each request (although rails does have query caching).
Both solutions only use active record so are database independent.
What do you need the total returned by the query for? if its pagination look into Will_paginate (Railscast) which can be extended with AJAX etc...
Try find_by_sql may that help.
Is #robots.size what you're looking for? Or Robot.count?
Otherwise, please clarify.
I think hakunin is right.
You can get no of row return by query by just chekcing the size of resulting array of query.
#robots = Robot.find_by_sql("Your sql")
or
#robots = Robot.find(:all , :conditions=>["your condiitons"] )
#robots.size or #robots.count