Yii2 hasMany with many conditions in join statement - join

I need to define more conditions in the JOIN statement.
How can I make this in Yii2 with a hasMany relation?:
... LEFT JOIN orders ON (customer.id = order.customer_id AND orders.position = 1) ...
I have a DataProvider for GridView. It look like this:
...
public function search($params)
{
$query = Customer::find()
->joinWith('orders');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $dataProvider;
}
...
Model:
...
public function getFirstOrder()
{
$query = $this->hasMany(Orders::className(), ['customer_id' => 'id']);
return $query;
}
...
Is it even possible?

public function search($params){
$activeDataProvider = new ActiveDataProvider([
"query" => Customer::find()
->joinWith('orders')
]);
// Valdate the search $params.
// Build your query depending on search params. I am assuming we get key => value pair in params
foreach($params as $key => $value){
$activeDataProvider->query->andWhere("`$key` = '$value'");
}
return $activeDataProvider;
}
I hope that helps you :)
You can also preview the generated sql using:
$command = $activeDataProvider->query->createCommand();
print_r ($command->sql);

Related

Orderby clause not working with drop down list in mvc

I am populating a drop down list using Linq and the orderby clause doesn't seem to work.
public List<Hello> getManagers()
{
var que = (from man in db.Table1
where man.Role == "Manager"
orderby man.Name
select new Hello
{
Managers = man.Name
}).Distinct().ToList();
return que;
}
Controller Class:
public ActionResult Index()
{
rp = new RequestProcess();
ViewBag.ID = fillSelectedList("", "ID", rp);
ViewBag.Managers = fillSelectedList("", "Managers", rp);
return View(""); //View 1
}
public static List<SelectListItem> fillSelectedList(string selValue, string type, RequestProcess rp )
{
List<SelectListItem> list = new List<SelectListItem>();
SelectListItem obj = new SelectListItem();
if (type == "Managers") {
var tempList= rp.getManagers();
tempList.ForEach(x =>
{
obj = new SelectListItem();
obj.Text = x.Managers;
obj.Value = x.Managers;
obj.Selected = x.Managers == selValue ? true : false;
list.Add(obj);
});
}
return list;
}
I am still receiving an un-ordered list. Any fixes?
The result is not ordered, because method Distinct does not return ordered results. What you need to do instead is to first call Disctinct, and only then OrderBy:
var que = (from man in db.Table1
where man.Role == "Manager"
select new Hello
{
Managers = man.Name
}).Distinct() // <- First distinct ...
.OrderBy(x => x.Managers) // <- ... then order by
.ToList();
As mentioned in the answer above, you need to sort the result after Distinct().
Also note that you are mixing Lambda expression and LINQ to Entities Queries... you may want to consider choosing one of them for consistency (though there is no syntax error if you mix them). This is the same query using lambda expression:
var que = _context.Table1
.Where(m => m.Role == "Manager")
.Select(h => new Hello { Managers = h.Name })
.Distinct()
.OrderBy(o => o.Managers)
.ToList();

Yii2 post request in controller

I have two submit buttons (submit1 and submit2). When I click "submit2", the controller should write a value (1) in a specific column (abgerechnet) in my db.
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
if(isset($_POST['submit2']) )
{
$request = Yii::$app->request;
$test= $request->post('test', '1');
}
return $this->redirect(['view', 'id' => $model->ID]);
}
return $this->render('update', [
'model' => $model,
]);
}
But when I click the button "submit2" the column "test" remains empty.
With the lines $request = Yii::$app->request;
$test= $request->post('test', '1');
it should write the value in the column "test".
If you want update the colum abgerechnet in your model based on $_POST['submit2'] then you should set the the value before invoking model->save()
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) ) {
if(isset($_POST['submit2']) )
{
$model->abgerechnet = 1;
}
$model->save();
return $this->redirect(['view', 'id' => $model->ID]);
}
return $this->render('update', [
'model' => $model,
]);
}

Dynamically apply filters on Entity Framework's entity using lambda expression

I need to have a method like this, where I can apply Where(x =>x. ...) and Include(x => x.RelatedEntity) and OrderBy(x=>x. ...) on a given entity.
Something like this:
public List<TEntity> ApplyFilter<TEntity>(TEntity entity,
List<filters> filters /* List of filters: 'filters' */)
where TEntity : BaseEntity
{
using (var db = new MyDbContext()){
var query = db.Set<TEntity>().AsQueryable;
//apply filters to 'query'
query.include(/*multiple related entities*/);
query.applyfilters(/*filters*/);
return query.ToList();
}
}
And I need to pass what I need to be filtered/included as lambda expressions.
NOTE: I searched a lot about how I can do it but I really wasn't able to find anything. I'm new to this part of C# / Entity Framework and I really didn't even know what keywords to search for.
Thank you for the help
You'll want to use a LINQ expression
public List<TEntity> ApplyFilter<TEntity>(
Expression<Func<TEntity, bool>> filter,
Expression<Func<TEntity, object>> orderBy,
params Expression<Func<TEntity, object>>[] includes) where TEntity : BaseEntity
{
using (var db = new MyDbContext())
{
var query = db.Set<TEntity>().AsQueryable();
query = query.Where(filter);
query = query.OrderBy(orderBy);
if (includes != null)
{
foreach (var include in includes)
{
query = query.Include(include);
}
}
return query.ToList();
}
}
To use the method:
ApplyFilter<TestObject>(
x => x.Prop1 == "foo",
x => x.Prop2,
x => x.Prop3, x => x.Prop4);
Like this?
var result = Repository.PurchaseProposalItem.GetDbSet();
if (filters.FilterByBrand) result = result.Where(p => p.GS_Product.GS_ProductBrand.PBr_Id == filters.BrandId);
if (filters.FilterByFamily) result = result.Where(p => p.GS_Product.GS_ProductFamily.PFa_Id == filters.FamilyId);
if (filters.FilterBySubFamily) result = result.Where(p => p.GS_Product.GS_ProductSubFamily.PSu_Id == filters.SubFamilyId);
if (filters.FilterByProductType) result = result.Where(p => p.GS_Product.Pro_Type == filters.ProductTypeEnum);
return result;

Multi-select foreign key filter

I'm trying to set up a multi-select filter on a foreign key in the symfony admin. I think I've set up everything correctly but for some reason it's not working:
public function configure()
{
parent::configure();
$s = Doctrine_Query::create()->
from('Status s')->
execute();
$status_choices = array();
foreach ($s as $key => $value) {
$status_choices[$value->getId()] = $value->getName();
}
$this->widgetSchema['status_id'] = new sfWidgetFormChoice(array('choices' => $status_choices, 'multiple' => true, 'expanded' => true));
$this->validatorSchema['status_id'] = new sfValidatorChoice(array('required' => false, 'choices' => $status_choices, 'multiple' => true));
}
public function getFields()
{
$fields = parent::getFields();
$fields['status_id'] = 'StatusId';
return $fields;
}
public function addStatusIdQuery(Doctrine_Query $query, $field, $values)
{
$fieldName = $this->getFieldName($field);
if (!empty($values))
{
$query->addWhereIn(sprintf('%s.%s', $query->getRootAlias(), $fieldName), $values);
}
}
Any help would be greatly appreciated...
In your validatorSchema, to validate data posted, you have to use array_keys($status_choices)
because values sent after posting the form are keys and not labels.
And the addWhereIn is not a Doctrine_Query method, use andWhereIn or whereIn
Hope that will help you

ValueInjecter with IQueryable<T>

I need to map IQueryable<User> to IQueryable<SimpleUser> with ValueInjecter.
Is this possible?
I tried:
return userRepo.GetUsers()
.Select(o => new SimpleUser().InjectFrom(o))
.Cast<SimpleUser>();
But this cannot be translated to a stored expression...well, the method InjectFrom.
Can automapper do this?
I want something similar to this:
return from i in userRepo.GetUsers()
select new SimpleUser{
i.UserId,
i.Name
};
but with using some kind of mapper tool.
Convert the collection to objects before doing the select and it should work. Updated using PredicateBuilder to show filtering and paging and Dynamic LINQ for sorting.
var predicate = new PredicateBuilder<User>.True();
if (!string.IsNullOrEmpty( typeFilter ))
{
predicate = predicate.And( u => u.Type == typeFilter );
}
if (!string.IsNullOrEmpty( nameFilter ))
{
predicate = predicate.And( u => u.Name.StartsWith( nameFilter ));
}
// assumes sortColumn matches one of your user properties and
// sortDirection is either "ASC" or "DESC"
string sortOrder = string.Format( "{0} {1}", sortColumn, sortDirection );
return userRepo.GetUsers()
.Where( predicate )
.OrderBy( sortOrder )
.Skip( (page-1) * usersPerPage )
.Take( usersPerPage )
.ToList() // force the query and make these objects
.Select(o => new SimpleUser().InjectFrom(o))
.Cast<SimpleUser>();

Resources