Most of the listboxes I use, make use of the lists function i.e.
->lists('id', 'name')
Is there a nice simple function for doing the same thing but also joins strings together? something like...
->lists('id', 'name'.' - '.'description')
I have a function that does this already, but it has to run through the database and make many queries before joining everything together...
Create an accessor in your model
public function getNameDescriptionAttribute($value)
{
return "$this->name - $this->description";
}
then when querying
->get()->lists('id', 'name_description')
Make sure you get() before listing.
Related
The actual thing that I need is an effective Delete method for the entities. In other words I would like to be able to write
cntx.Orders.Where(item => item.Category == "Custom1").Delete();
and that is supposed to delete all the records from the table Orders where the Category column value is equal to "Custom1". I don't really care if it will do it right away or after calling cntx.SaveChanges(). And, yes, the query is supposed to be efficient, something like
DELETE FROM Orders WHERE Category = "Custom1"
I know about at least 3 extension libraries for the Entity Framework Core which advertise such abilities but non of them work for Android. Now, I'm thinking how difficult it actually is to write a Delete extension method myself. Can anybody help me with an example? Apparently I should be able to add something to the expression tree which will be called by the framework and in my turn I would generate "DELETE FROM Orders" and then "Where(item => item.Category == "Custom1")" would be replaced by the "WHERE Category = "Custom1""
So, apparently everything should start from
public static class QueryExtension {
public static void Delete<T>(IQueryable<T> objThis) {
// The big mystery is what to call here to ensure that "DELETE FROM [TableName]"
// is entered to the right place of the expression tree and then
// we somehow need to execute the complete statement here or delegate it to SaveChanges
}
}
I sort of realize that translation of the expression tree into a SQL statement happens somewhere in the expression visitor. That is most likely wrapped into some kind of statement compiler of the Entity Framework. I have no idea where all those entry points to write an extension like I need.
Is it possible to extend DbFunctions, assuming you are using existing DbFunctions as helper methods. I am essentially rewriting the exact same line of sql code again and again. Are there any alternatives?
Update:
Here is an example of what I'm trying to do, but I want to define my own Add function, not use one that I've constructed in my database
var locations = context.Data.Where(e => Functions.Add(e.X, e.Y) >= 10)
Yes of course you can extend it. Class DbFunctions only contains code that helps the provider of your IQueryable to translate the expression into SQL.
An IEnumerable holds all code to create an Enumerator for you upon request. The Enumerator represents a sequence. Upon request it will give you the first element of the sequence, and once you've got an element it will give you the next one (provided there is one).
An IQueryable works differently. Usually an IQueryable is not meant to be performed by your process, but for instance a database, a remote web site, a CSV file controller, etc.
That is why you need to tell an object that produces IQueryables for which process it must create the IQueryable. In case of Entity Framework you inform the DbContext which database to use.
The IQueryable object holds an Expression to be performed and a Provider. The provider knows which process will perform the query. It also knows how to translate the Expression into the format that the other process understands. Quite often this will be SQL.
If you investigate the remarks section of the MSDN descriptions of IQueryable functions like Where, GroupBy, Select, you'll see that most of these functions will only change the Expression.
As long as you don't ask for the Enumerator, usually implicitly by asking for the first element of a sequence, like in ToList, foreach, FirstOrDefault, etc, the Provider has nothing to do.
But once you ask for the Enumerator, the Expression will be translated by the Provider, who will use the translation to query the data from the other process and create an Enumerator object that can give you the first element of the sequence, and the next ones.
DbFunctions are used when the Provider translates the Expression into SQL. If you create a Queryable with DbFunctions and in your debugger look at the created Expression, you'll still find the used DbFunctions.
The DbFunctions only translate the input into SQL. If does not perform the query itself. The translation is done in local memory.
Having understood this, you can use any function as long as it only changes the Expression into new Expressions into formats that your provider understands.
This means you can't use any of your own functions, or classes. There are even several LINQ functions you can't use
See supported and non-supported LINQ methods
However, if your extension functions input an IQueryable and output an IQueryable, then your extension function will only change the Expression. As long as you fill the Expression with supported LINQ methods you're fine
So if you want to extend IQueryable with a function that returns an IQueryable containing only the invoice that are due to day:
public static IQueryable<Invoice> WhereDueToday(this IQueryable<Invoice> invoices)
{ // returns all invoices that must be paid today
return invoices
.Where(invoice => DbFunctions.TruncateTime(invoice.DueDate) == DateTime.Today);
}
Usage:
IQueryable<Invoice> invoices = dbContext.Invoices
.Where(invoice => ..);
IQueryable<Invoice> invoicesDueToDay = invoices
.WhereDueToday();
You can define a method that returns an Expression and use that in your where clause. Since you want to pass different properties of the object in you can't just write one expressions
public Expression<Func<T, bool>> MyFunc<T>(Expression<T, int> property1, Expression<T, int> property2, int greaterThan)
{
// Build expression tree
}
I realise "Build Expression tree" isn't hugely useful, but if you don't really want to do add writing out the code to build "add" isn't going to help you either.
If there are just a couple of combinations it might be easier to just hard code for those
public Expression<Func<T, bool>> MyFunc<T>(PropertiesEnum p, int greaterThan)
{
switch(p)
{
case (p.XandY):
return item => (item.X + item.Y) > greaterThan;
case (p.XandZ):
return item => (item.X + item.Z) > greaterThan;
case (p.YandZ):
return item => (item.X + item.Z) > greaterThan;
// other cases
}
}
You would call this like:
var locations = context.Data.Where(MyFunc(PropertiesEnum.XandY, 10));
I am running the following Eloquent query in a function, and nothing is being returned.
$foo = Foo::whereId(idHere)->first();
Log::info($job);
Null is being returned, and I know that the object exists, I can access it in other places (controllers, views, etc.) Am I not including something that needs to be included in order to make Eloquent queries work? Here is what the include looks like at the top of this file:
use App\Core\Models\Foo;
use Log;
use Carbon\Carbon;
use BAR\Http\Controller; //CUSTOM CONTROLLER THING, NOT THE PROBLEM
Sometimes I have complicated find procedures and I'm feeling dirty to repeat this code in my Controller.
Now I am thinking, it is possible to do something like this:
class User extends BaseUser
{
private static function getTable()
{
return Doctrine_Core::getTable('User');
}
public static function findAll()
{
return getTable()->findAll();
}
public function currentEnrolments() {
$query = Doctrine_Query::create()
->from('Enrolment e')
->where('e.user_id = ?', $this->id)
->addWhere('e.finish_date IS NULL');
return $query->execute();
}
}
Is this a good practice? Or should I only put non static members like the query I have shown?
Generally, if it saves you time, there nothing to lose and every minute you can save to gain.
Functions like getTable and findAll are probably not saving you a lot, but custom queries for finding stuff more specific to your application will definitely be worth it.
I have got pretty much the same approach.
I wouldn't bother with your static proxies of getTable() and findAll().
That doesn't really add any value to your code
I, personnaly, never call findAll() on any model object as you will generally need
to cross-check against a foreign key
paginate / sort
...
regarding your currentEnrolments() function, this is worth doing as you have a bit of logic on this ->addWhere('e.finish_date IS NULL'), thus explaining you can't use the "magic" Doctrine relation ->Enrolment. Maybe this is something Doctrine 2 is resolving, need to check this out ...
Regards
Basically I'd be looking to implement a method like this.
IQueryAble GetQuery<T>(Entities db) or extension method Entities.GetQuery<T>()
This way you could do things like this
public IQueryable<T> GetAll()
{
return yourEntityClasses.GetQuery<T>();
}
which would return a SELECT * FROM query expression and obviously from there you could make addtional generic methods for sorting, pagination, where expressions, etc on top of this would save you from having to repeat the code for these methods for each table. I know SubSonic3 does a very good job of this, but was trying to duplicate some of the functionality in an EntityFramework project I am working on. Only thing I see in EF is CreateQuery and ObjectQuery but both of those require you to pass a querystring in which would require you to know the table name.
Well it is possible to get the string that you need to put into the CreateQuery method automatically.
Basically it is just string.Format("[{0}]",entitySetName);
How do you get the entity set name, assuming you have don't use something called MEST, most people don't, you can use some a functions I wrote in this Tip to get the EntitySet for T and from that the name.
Once you do that it should be pretty trivial for you to write the Extension Method
i.e.
public static IQueryable<T> GetAll<T>(this ObjectContext context)
{
var wkspace = context.MetadataWorkspace;
EntitySet set = wkspace
.GetEntitySets(wkspace.GetCSpaceEntityType<T>())
.Single();
return context.CreateQuery<T>(string.Format("[{0}]",set.Name);
}
See the above tip for the other functions used.
Hope this helps
Alex