Intersect or Except methods in linq not working in MYSQL - mysql

I am using entity framework with mysql. I have to use Intersect in one of the query but it throws the error "Specified method is not supported.". Can anyone suggest alternatives other than taking data to memory and apply Intersect on that.
public List<share> GetFeed(List<long> UserRules, List<long> ListedShares, string AuthorID)
{
List<share> listshare = DbContext
.shares
.Where(x => UserRules.Intersect(x.share_rules.Select(y => y.rule_id)).Any())
.ToList();
return listshare;
}

Specified method is not supported. means that EntityFramework is not able to translate it to SQL query. Actually, in most cases, it is possible to convert it to Contains, which is supported. You should change your method to match:
public List<share> GetFeed(List<long> UserRules, List<long> ListedShares, string AuthorID)
{
List<share> listshare = DbContext
.shares
.Where(x => x.share_rules.Any(y => UserRules.Contains(y.rule_id)))
.ToList();
return listshare;
}

Related

How to map database function to Entity Framework Core property

my problem is that i can't map database function to use it in object property like computed column but for different tables with relation. My relation is SizeItem to Review (one to many)
I have IEntityTypeConfiguration
internal class SizeItemConfiguration : IEntityTypeConfiguration<SizeItem>
{
public const string TableName = "size_items";
public void Configure(EntityTypeBuilder<SizeItem> builder)
{
builder.ToTable(TableName);
builder.Property(p => p.Id)
.UseHiLo("size_item_hilo");
}
}
And want to compute an average rating from Review entities related to a SizeItem.
I tried to find examples to use database functions and EF Core functions but nothing works.
How can I get computed SizeItem.AverageRating for every sql command? May be code will looks like:
builder.Property(p => Functions.Average(p.Reviews.Select(x => x.Rating)));
User-defined function mapping doesn't work for me because I'm using Repository pattern.

How do I return a union as an Active Record object?

I have these union in my controller :
$expression = new Expression('"News"');
$featuredNews2= news::find()
->alias('ne')
->select(['ne.title', 'ne.content','ne.featuredOrder', 'category'=>$expression])
->innerJoinWith('featuredOrder1');
$expression2 = new Expression('"Event"');
$featuredEvents2 = event::find()
->select(['ev.title', 'ev.content','ev.featuredOrder','category'=>$expression2])
->from('event ev')
->innerJoinWith('featuredOrder2');
$union = $featuredNews2->union($featuredEvents2);
The relation in model :
news model
public function getFeaturedOrder1()
{
return $this->hasOne(Featured::className(), ['featuredOrder' => 'featuredOrder']);
}
event model
public function getFeaturedOrder2()
{
return $this->hasOne(Featured::className(), ['featuredOrder' => 'featuredOrder']);
}
I need to return the query as an Active Query because I need to access my model's method e.g : $model->featuredOrder1->preview in my view.
The following works but it returns an array, as the result I can't access my model's method :
$unionQuery = (new \yii\db\Query)->select('*')
->from($union)
->orderBy('featuredOrder')->all(\Yii::$app->db2);
I have two questions :
How to return the equivalent $unionQuery above but as an active query object? I have googled and search on SO but what I found is how to return it as array.
This is out of curiosity, I wonder why I should provide my db connection as argument in my $unionQuery all() method above. If I didn't use an argument that point to db2, it will look for table name inside my db database instead ( db is my parent database, this db2 is my module's database/the correct one). This only happen with a union. My news and event model already have this in getdb() function:
return Yii::$app->get('db2');
update
I've tried this too :
$unionProvider = (new ActiveQuery(Featured::className()))->select('*')
->from(['union' => $featuredEvents2->union($featuredNews2)])
->orderBy('featuredOrder');
With this relation in featured model:
public function getNews()
{
return $this->hasOne(News::className(), ['featuredOrder' => 'featuredOrder']);
}
public function getEvents()
{
return $this->hasOne(Event::className(), ['featuredOrder' => 'featuredOrder']);
}
and in the view, I tried this :
foreach($unionProvider as $key=>$model){
echo $model->news->title;
}
but get this error : Trying to get property of non-object
Update 2
I forgot to add ->all() in my $unionProvider, but after that I got this error instead : PHP Fatal Error – yii\base\ErrorException
Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes)
Might be something wrong with my query? Can't figure it out
You can try using pure SQL. Plus you can test to see if it is returning the correct results and then add it in the statement below.
$customers = Customer::findBySql('SELECT * FROM customer')->all();
Learn more in yii docs

How to use constant in the ON condition in Yii2 hasMany relation

I try to create a polymorphic association, what is common in Rails but unfortunately not in Yii2. As part of the implementation I need to define the relation:
public function getImages()
{
return $this->hasMany(RecipeImage::className(),
['imageable_id' => 'id', 'imageable_type' => 'Person']);
}
But this doesn't work, because 'Person' is treated as an attribute of the current model, but it is a constant (class name for the polymorphic association).
If I try to use 'andWhere' it adds the condition of course in a WHERE clause instead of the ON clause, causing that only records with existing image returned.
public function getImages()
{
return $this->hasMany(RecipeImage::className(), ['imageable_id' => 'id'])->
andWhere(['imageable_type' => 'Ingredient']);
}
How can I define the relation? There is no andOn method.
In this case you can modify ON condition with andOnCondition method:
public function getImages()
{
return $this->hasMany(RecipeImage::className(), ['imageable_id' => 'id'])
->andOnCondition(['imageable_type' => 'Person']);
}
Official docs:
andOnCondition:

Specified method is not supported MySql Entity Framwork 6

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);

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();