When writing a where condition on an Entity Framework context object, is there a shorthand way of testing all the columns, sort of like this:
context.tableName.where(t => t.AnyColumn.Contains(...))
Or am I forced to test each column individually?
There is no out-of-the-box way to do that but you can write your own method which will use reflection to get the list of your model's properties and check each of them
I don't know that this is possible you may have to search each field individually, but why not search for a value in a specific column instead of searching the whole table, it reduces the room for error and makes for a quicker query
Related
I've got a little situation that I'd like to take care of, but I don't even know if it's possible.
In my app, I have one model that can take a parameter value, this parameter can be either a string or an integer or a boolean.
Instead of doing two string column (in my migration) with one labeled as "type" (the type - really !) and the other labeled as "value" (for the... value ! Yes !) i was wondering if it was possible that there is only the column value remaining, with polymorphics types in there.
The Model represent a property on a taks. Theses properties can be : is this task's open (type "boolean" and value "true" for exemple) ? Does this task has a percentage (type "integer", value "20") ? Note that the table also have a column name.
Polymorphism in Rails is more about associations where the class of the related item is unknown - not database columns with a dynamic type.
While is possible to implement a dynamic column in a relational database using two string columns value and value_type and use a custom getter to typecast value its going to get really messy. Another possibility is to use a something like a HSTORE or JSON column type but again do you really need it? Is there a better way to structure your business logic than trying to jam everything into a single column?
I'm guessing that what you may be looking for is something like an enum to denote the state of your model.
class Ticket < ActiveRecord::Base
enum status: [ :open, :closed, :pending, :active ]
end
This would use an integer column named status.
If you wanted to store additional information it would be prudent to use an additional database column. Like if you want to monitor the progress you would create an integer database column named tickets.progress.
For your answer, yes it is possible, but don't do it that way.
It is possible to use string for all different cases:
"integer:100", "integer:23", etc.
"boolean:true", "boolean:false", etc.
you will need to identify each data type(use concat)and convert to a right type and only then you can use the value.
But it is completely wrong and its implementation is going to be very complicated. I strongly recommend not to use this example or something similar.
I think that this is a wrong database structure.
In general, if you have a case in which you have a column that you think can contain more than one data type - something is wrong in your database and you should make a 'redesign' of your database.
Usually the best practice is to separate to different columns. In your case, your column can get different types, each type represents different information. I think your table should have these columns:
status_id - will reference to another table, Status that will contain all possible statuses(if there are more than 2 options).
progress/percentage - integer.
My answer isn't relevant for relational databases.
Normally we use Model.where(name: 'John') to find records. Let's say I have a method inside the model named status which does some calculations and output a string. How can I use that in the where? Now if I use Model.where(status: 'active') it says PG::UndefinedColumn: ERROR: column model.status does not exist
No, you can't. where is for SQL conditions, if you calculate your status in Ruby, you can't use it in where.
If what you ask is how to have status applied as a filter by the SQL server before retrieving the records, you can't.
One option indeed, is to retrieve all the records and then use select to get what you want. That is very inefficient.
One other option is to write a fragment of SQL logic and plug that straight into a where. That is not easy but very efficient.
One last solution is to have that status be computer for you by a before_save and stored in the table. You can then use a regular where to filter which records you want. The downside of this, is that you have a new extra column.
I have a model to which I need to create a default scope. I am unsure of the best way to write this scope but I will explain how it needs to work.
Basically I need to get all items of the model and if two items have the same "order" value then it should look to the "version" field (which will contain, 1, 2, 3 etc) and pick the one with the highest value.
Is there a way of achieving this with just a scope?
Try this code:
scope :group_by_order, -> { order('order ASC').group('order') }
default_scope, { (group_by_order.map{ |key,values| values.order('version DESC') }.map{|key, values| values - values[1..-1]}).values.flatten }
Explanation Code:
order by "order" field.
group by "order" field.
map on the result hash, and order each values by "version" field
map again on values, and remove from index "1" to the end.
get all values, and flatten them
A word of caution using default scopes with order. When you performs updated on the collection such as update_all it will use the default scope to fetch the records, and what you think would be a quick operation will bring your database to its knees as it copies the rows to a temporary table before updating.
I would recommend just using a normal scope instead of a default scope.
Have a look at Select the 3 most recent records where the values of one column are distinct on how to construct the sql query you want and then put that into a find_by_sql statemate mentioned in How to chain or combine scopes with subqueries or find_by_sql
The ActiveRecord order method simply uses the SQL ORDER function which can have several arguments. Let's say you have some model with the attributes order and version then the correct way order the records as you describe it, is order(:order, :version). If you want this as the default scope would you end up with:
default_scope { order(:order, :version) }
First, default_scopes are dangerous. They get used whenever you use the model, unless you specifically force 'unscoped'. IME, it is rare to need a scope to every usage of a model. Not impossible, but rare. And rarer yet when you have such a big computation.
Instead of making a complex query, can you simplify the problem? Here's one approach:
In order to make the version field work, you probably have some code that is already comparing the order fields (otherwise you would not have unique rows with the two order fields the same, but the version field differing). So you can create a new field, that is higher in value than the last field that indicated the right entity to return. That is, in order to create a new unique version, you know that you last had a most-important-row. Take the most-important-rows' sort order, and increment by one. That's your new most-important-rows' sort order.
Now you can query for qualifying data with the highest sort order (order_by(sort_order, 'DESC').first).
Rather than focus on the query, focus on whether you are storing the right data, that can the query you want to achieve, easier. In this case, it appears that you're already doing an operation that would help identify a winning case. So use that code and the existing database operation, to reduce future database operations.
In sql you can easily order on two things, which will first order on the first and then order on the second if the first thing is equal. So in your case that would be something like
select * from posts order by order_field_1, version desc
You cannot name a column order since it is a sql reserved word, and since you did not give the real column-name, I just named it order_field_1.
This is easily translated to rails:
Post.order(:order_field_1, version: :desc)
I would generally advice against using default_scope since once set it is really hard to avoid (it is prepended always), but if you really need it and know the risks, it is really to apply as well:
class Post < ActiveRecord::Base
default_scope { order(:order_field_1, version: :desc) }
end
This is all actually documented very well in the rails guides.
The scenario:
I have a considerable amount of entities as models in CodeFirst mapped to the database fieldname with the Attribute [Column("str")].
I have a bunch of Reporting Service Reports (in local-mode) with the DataSets mapped to the database field names.
I can't pass direct results of linq queries to those reports with the ToList() method because of the field names. What I can do (and I'm trying to avoid) is to type select new for each object; or run each query via a different datasource.
Question:
I would like to know if there is any trick to have a IQueryable object with the original field names instead of the property names. Something like a dynamic select new.
Any suggestions will be appreciated.
No, there isn't. The database column names either have to match the property name, or you have to use the Column attribute to make them line up. That's your only choices.
Suppose you declare a simple "license" table in a doctrine schema, consisting say of 3 fields, name, licenseNumber, expirationDate.
You can create a simple query to instantiate the collection of license objects. But what if you wanted to add a "virtual" field to it, for example,select *, (now() > expirationDate) as expired from license (in DQL, I'm using SQL as shorthand here).
Is there any way to get doctrine to make the "expired" calculated field retrievable as an attribute of the object? This is a trivial example to illustrate the point, but it could be quite helpful for more complicated calculated queries, or else I'm misunderstanding something.
No, there is no way to do what you are asking without adding a custom method to hydrate the "virtual column". Take a look at this SO post, as it gives an excellent example on how to hydrate arrays with your "virtual column".
You can also add the "virtual column" as a member object to the respective class and hydrate it like this example demonstrates.
You can also use a view with such a column and map your model to it instead of a db table