Using max() function with entity framework throws an exception - entity-framework

So I need to get the max value of a column (or the last one) using entity framework and both of these queries throw exceptions:
(The ID I'm trying to retrieve is of type varchar, but it works in raw sql, I think
it should work here too)
This one:
string maxCurrentID = db.reservations.Max().ReservationID;
Throws this:
The specified method 'EntityClub_.reservacion Maxreservacion' on the type 'System.Linq.Queryable' cannot be translated into a LINQ to Entities store expression because no overload matches the passed arguments.
and this one:
string maxCurrentID = db.reservations.LastOrDefault().ReservationID;
LINQ to Entities does not recognize the method 'EntityClub_.reservacion LastOrDefaultreservacion' method, and this method cannot be translated into a store expression.
How can I obtain the expected values?

var maxReservationId=db.reservations.Max(u =>(int?)u.ReservationID) ?? 0;
if there is no data in table it replaces null with 0

You aren't asking for the highest ReservationID, you're trying to get the highest Reservation, and getting its ReservationID. EF does not understand what "the highest Reservation" means.
var maxReservationID = db.reservations.Max(r => r.ReservationID);
or
var maxReservationID = db.reservations.Select(r => r.ReservationID).Max();
should work.

Related

EF Core completely ignores my selected properties in select

As I understand it, the following code should generate a query containing only the RouteId, RouteNo, and ShipId
var tow = (from t in _context.AllTowData
where t.RouteId == id
orderby t.RouteNo descending
select new TowDefaults {
Id = t.RouteId,
TowNo = t.RouteNo,
ShipId = t.ShipId,
LastTow = t.RouteNo
})
.FirstOrDefault();
However, I get:
SELECT v.route_id, v.route_no, v.tow_id, v.analysis_complete, v.checks_complete, v.cpr_id, v.date_created, v.date_last_modified, v.factor, v.fromportname, v.instrument_data_file, v.instrument_id, v.internal_number, v.mastername, v.message, v.miles_per_division, v.month, v.number_of_samples, v.number_of_samples_analysed_fully, v.prop_setting, v.route_status, v.sampled_mileage, v.serial_no_per_calendar_month, v.ship_speed, v.silk_reading_end, v.silk_reading_start, v.toportname, v.tow_mileage, v.validity, v.year
FROM view_all_tow_data AS v
WHERE v.route_id = '#__id_0'
ORDER BY v.route_no DESC
LIMIT 1
That's every column except the explicitly requested ShipId! What am I doing wrong?
This happens using both a SQL Server and a PostGres database
The property ShipIdis not mapped, either by a [NotMapped] annotation or a mapping instruction. As far as EF is concerned, the property doesn't exist. This has two effects:
EF "notices" that there's an unknown part the final Select and it switches to client-side evaluation (because it's a final Select). Which means: it translates the query before the Select into SQL which doesn't contain the ShipId column, executes it, and materializes full AllTowData entities.
It evaluates the Select client-side and returns the requested TowDefaults objects in which ShipId has its default value, or any value you initialize in C# code, but nothing from the database.
You can verify this by checking _context.AllTowData.Local after the query: it will contain all AllTowData entities that pass the filter.
From your question it's impossible to tell what you should do. Maybe you can map the property to a column in the view. If not, you should remove it from the LINQ query. Using it in LINQ anywhere but in a final Select will cause a runtime exception.

Foreign Key Object Missing in LINQ GroupBy?

I am using GroupBy in my LINQ queries. My query is working fine, except my foreign key objects are missing. Then, I tried to add Include in my query. Following is my code:
public ActionResult GetEmployees()
{
var Emloyees = db.Employees.AsQueryable();
Emloyees.GroupBy(e=> new {e.JobTitleId, e.GenderId})
.Select(tr => new MyObject
SalaryTotal = tr.Sum(r=>r.Salary)
}).Include(tr=>tr.JobTitle).Include(tr=>tr.Gender).ToList();
}
I am getting this exception:
The result type of the query is neither an EntityType nor a CollectionType with an entity element type. An Include path can only be specified for a query with one of these result types.
I tried to add it before GroupBy and directly in db.Employees.AsQueryable(), but nothing worked. What am I doing wrong?
The problem is that you are doing a projection with the .Select(...), after which your includes cannot be resolved. The result of that query will be a list MyObject, which does not work for includes that are actually on Employee.
So Try it like this:
Emloyees
.GroupBy(e=> new {e.JobTitleId, e.GenderId})
.Select(tr => new MyObject {
SalaryTotal = tr.Sum(r=>r.Salary),
JobTitle = tr.FirstOrDefault().JobTitle,
Gender = tr.FirstOrDefault().Gender
}).ToList();
You will have to extend MyObject with 2 additional properties, but the result of your query will be what you want (I assume).

mybatis - Passing multiple parameters on #One annotation

I am trying to access a table in my Secondary DB whose name I am obtaining from my Primary DB. My difficulty is to pass the "DB-Name" as a parameter into my secondary query, (BTW I am using MyBatis annotation based Mappers).
This is my Mapper
#SelectProvider(type = DealerQueryBuilder.class, method = "retrieveDealerListQuery")
#Results({
#Result(property="dealerID", column="frm_dealer_master_id"),
#Result(property="dealerTypeID", column="frm_dealer_type_id", one=#One(select="retrieveDealerTypeDAO")),
#Result(property="dealerName", column="frm_dealer_name")
})
public List<Dealer> retrieveDealerListDAO(#Param("firmDBName") String firmDBName);
#Select("SELECT * from ${firmDBName}.frm_dealer_type where frm_dealer_type_id=#{frm_dealer_type_id}")
#Results({
#Result(property="dealerTypeID", column="frm_dealer_type_id"),
#Result(property="dealerType", column="frm_dealer_type")
})
public DealerType retrieveDealerTypeDAO(#Param("firmDBName") String firmDBName, #Param("frm_dealer_type_id") int frm_dealer_type_id);
The firmDBName I have is obtained from my "Primary DB".
If I omit ${firmDBName} in my second query, the query is trying to access my Primary Database and throws out table "PrimaryDB.frm_dealer_type" not found. So it is basically trying to search for a table named "frm_dealer_type" in my Primary DB.
If I try to re-write the #Result like
#Result(property="dealerTypeID", column="firmDBName=firmDBName, frm_dealer_type_id=frm_dealer_type_id", one=#One(select="retrieveDealerTypeDAO")),
It throws an error that Column"firmDBName" does not exist.
Changing ${firmDBName} to #{firmDBName} also did not help.
I did refer to this blog - here
I want a solution to pass my parameter firmDBName from my primary query into secondary query.
The limitation here is that your column must be returned by the first #SELECT.
If you look at the test case here you will see that parent_xxx values returned by the first Select.
Your DealerQueryBuilder must select firmDBName as a return value and your column must map the name of the return column to that.
Your column definition is always wrong, it should be:
{frm_dealer_type_id=frm_dealer_type_id,firmDBName=firmDBName} or whatever it was returned as from your first select.
Again you can refer to the test case I have above as well as the documentation here http://www.mybatis.org/mybatis-3/sqlmap-xml.html#Nested_Select_for_Association

Possible bug in breeze 1.4.14

I haven't tested this against the 1.4.16 release that came out a couple of weeks ago but there is nothing in the release notes about it.
The problem occurs with predicates where the value you are comparing is identical to the name of a property on any entity that breeze knows about. A simple test case is :
var query = breeze.EntityQuery.from('Items');
var pred = breeze.Predicate.create('name', breeze.FilterQueryOp.Contains, searchTerm);
query = query.where(pred);
Where searchTerm is equal to any string other than "name" this produces an oData query as below:
Items?$filter=(substringof(%27somevalue%27%2CName)%20eq%20true)
but if searchTerm = "name" then it produces the following query
Items?$filter=(substringof(Name%2CName)%20eq%20true)
Which istead of comparing the string 'name' against the property Name, it compares the property Name with itself.
I have not tested every operator but as far as I can tell it does not matter which you use you get the same behaviour.
You also get the same problem when querying navigation properties but it usually results in an invalid query. Below is a predicate for the same entity but against a navigation property tags that contains a collection of ItemTag entities that have a "Tag" property on them.
breeze.Predicate.create('tags', breeze.filterQueryOp.Any, 'tag', breeze.filterQueryOp.Contains, searchTerm)
It works fine for any searchTerm other than "tag" where it produces an oData request as below:
Items?$filter=Tags%2Fany(x1%3A%20substringof(%27somevalue%27%2Cx1%2FTag)%20eq%20true)
but if the searchTerm is "tag" then it requests:
Items?$filter=Tags%2Fany(x1%3A%20substringof(Tag%2Cx1%2FTag)%20eq%20true)
which produces an error of "Could not find a property named 'Tag' on type 'Item'" because the property Tag exists on the ItemTag entity.
In short breeze seems to infer that any search term that is identical to the name of a property it knows about, refers to that property rather than being a string literal value.
Has anyone else encountered this?
Is this a bug, or is there a way to explicitly tell breeze to interpret that value as a string literal and not a reference to a property?
I am not sure it is relevant as the server seems to be responding correctly to the requests and it is breeze that is creating incorrect requests but on the server side I am using Web API oData controllers with EF as ORM data layer.
Try
var pred = breeze.Predicate.create('name', breeze.FilterQueryOp.Contains,
{ value: searchTerm, isLiteral: true} );
This is described here ( under the explanation of the value parameter):
http://www.breezejs.com/sites/all/apidocs/classes/Predicate.html#method_create
if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal.
In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value' property and an 'isLiteral' property set to either true or false.
Breeze also tries to infer the dataType of any literal based on context, if this fails you can force this inference by making the value argument an object with a 'value' property and a 'dataType'property set
to one of the breeze.DataType enumeration instances.
The reason for this logic is to allow expressions where both sides of the expression are properties. For example to query for employees with the same first and last name you'd do this:
var q = EntityQuery.from("Employees")
.where("lastName", "==", "firstName");
whereas if you wanted employees with a lastName of 'firstName' you'd do this:
var q = EntityQuery.from("Employees")
.where("lastName", "startsWith", { value: "firstName", isLiteral: true })

EF4 inheritance and Stored procedures

I implemented inheritance with a discriminator field so all my records are in the same table. My basetype is Person (also the name of the table) and Driver and Passenger inherit from it. I receive instances of the correct type (Driver and Passenger) when I perform a query on the object context to Person. example:
var q = from d in ctx.Person
select d;
But I also create a function that calls a stored procedure and mapped the output of the function to the type Person. But now I get a list of Person and not Drivers or Passengers when I execute this method.
Anybody an idea how to solve this or is this a bug in EF4?
AFAIK, you can't use discriminator mapping (e.g TPH) when dealing with stored procedure mappings.
The stored procedure must be mapped to a complex type or custom entity (e.g POCO), the mapping cannot be conditional.
What you could do is map it to a regular POCO, but then project that result set into the relevant derived type (manual discrimination).
E.g:
public ICollection<Person> GetPeople()
{
var results = ExecuteFunction<Person>(); // result is ObjectResult<Person>
ICollection<Person> people = new List<Person>();
foreach (var result in results)
{
if (result.FieldWhichIsYourDiscriminator == discriminatorForDriver)
{
people.Add((Driver)result);
}
// other discriminators
}
}
If your always expecting a collection of one type (e.g only Drivers), then you wouldn't need the foreach loop, you could just add the range. The above is in case you are expecting a mixed bag of different people types.
Would be interested to see other answers, and if there is a better way though - but the above should work.