I have a complex entity framework query (filter, unions, calculations, ...):
IQueryable<ViewModel> query = from a in db.Entity1
where ...
select new ViewModel
{
field1: a.field1,
field2: a.field1*2 // Calculation example
};
other_part_of_my_application.DataSource = query;
This query object is an IQueryable. This means the query is not executed at this time. The object is send to another part of my application which apply additional filters, sorting and pagination.
I would like to write my query in raw SQL. Is there a way to do that without changing the other part of my application ?
I would like to do something like this:
IQueryable<ViewModel> query = I_Dont_know_what<ViewModel>("SELECT field1, (field1*2) as field2 From Entity1 Where ...");
other_part_of_my_application.DataSource = query;
My question is what should i put instead of "I_Dont_know_what" ?
Thanks
Related
I like the idea of Named Queries in JPA for static queries I'm going to do, but I often want to get the count result for the query as well as a result list from some subset of the query. I'd rather not write two nearly identical NamedQueries. Ideally, what I'd like to have is something like:
#NamedQuery(name = "getAccounts", query = "SELECT a FROM Account")
.
.
Query q = em.createNamedQuery("getAccounts");
List r = q.setFirstResult(s).setMaxResults(m).getResultList();
int count = q.getCount();
So let's say m is 10, s is 0 and there are 400 rows in Account. I would expect r to have a list of 10 items in it, but I'd want to know there are 400 rows total. I could write a second #NamedQuery:
#NamedQuery(name = "getAccountCount", query = "SELECT COUNT(a) FROM Account")
but it seems a DRY violation to do that if I'm always just going to want the count. In this simple case it is easy to keep the two in sync, but if the query changes, it seems less than ideal that I have to update both #NamedQueries to keep the values in line.
A common use case here would be fetching some subset of the items, but needing some way of indicating total count ("Displaying 1-10 of 400").
So the solution I ended up using was to create two #NamedQuerys, one for the result set and one for the count, but capturing the base query in a static string to maintain DRY and ensure that both queries remain consistent. So for the above, I'd have something like:
#NamedQuery(name = "getAccounts", query = "SELECT a" + accountQuery)
#NamedQuery(name = "getAccounts.count", query = "SELECT COUNT(a)" + accountQuery)
.
static final String accountQuery = " FROM Account";
.
Query q = em.createNamedQuery("getAccounts");
List r = q.setFirstResult(s).setMaxResults(m).getResultList();
int count = ((Long)em.createNamedQuery("getAccounts.count").getSingleResult()).intValue();
Obviously, with this example, the query body is trivial and this is overkill. But with much more complex queries, you end up with a single definition of the query body and can ensure you have the two queries in sync. You also get the advantage that the queries are precompiled and at least with Eclipselink, you get validation at startup time instead of when you call the query.
By doing consistent naming between the two queries, it is possible to wrap the body of the code to run both sets just by basing the base name of the query.
Using setFirstResult/setMaxResults do not return a subset of a result set, the query hasn't even been run when you call these methods, they affect the generated SELECT query that will be executed when calling getResultList. If you want to get the total records count, you'll have to SELECT COUNT your entities in a separate query (typically before to paginate).
For a complete example, check out Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs.
oh well you can use introspection to get named queries annotations like:
String getNamedQueryCode(Class<? extends Object> clazz, String namedQueryKey) {
NamedQueries namedQueriesAnnotation = clazz.getAnnotation(NamedQueries.class);
NamedQuery[] namedQueryAnnotations = namedQueriesAnnotation.value();
String code = null;
for (NamedQuery namedQuery : namedQueryAnnotations) {
if (namedQuery.name().equals(namedQueryKey)) {
code = namedQuery.query();
break;
}
}
if (code == null) {
if (clazz.getSuperclass().getAnnotation(MappedSuperclass.class) != null) {
code = getNamedQueryCode(clazz.getSuperclass(), namedQueryKey);
}
}
//if not found
return code;
}
I've ported some of my Entity from JPA to document and now porting some of my queries.
here is the JPA query:
em.createQuery("select distinct c from CustomerImpl c left join fetch c.addresses ca where (:name is null or c.firstName LIKE :name or c.lastName LIKE :name) and (:ref is null or c.externalReference LIKE :ref) and (:city is null or ca.city LIKE :city) order by c.firstName").setParameter("name", name).setParameter("ref", customerRef).setParameter("city", city).getResultList();
below is my attempt :
Criteria orNameCriteria = new Criteria().orOperator(Criteria.where("firstName").is(null), Criteria.where("firstName").is(name), Criteria.where("lastName").is(name));
Criteria orCustomerRefCriteria = new Criteria().orOperator(Criteria.where("externalReference").is(null), Criteria.where("externalReference").regex(customerRef,"i"));
Criteria orAddress = new Criteria().orOperator(Criteria.where("addresses.city").is(null), Criteria.where("addresses.city").regex(city, "i"));
Query nameq = new Query(new Criteria().andOperator(orNameCriteria,orCustomerRefCriteria,orAddress));
this query return zero size arraylist. I've then changed the orNameCriteria to use is clause and making sure the data contained in name variable has / as suffix and prefix. That didn't work as well.
but queries from mongoVue and RockMongo clients :
{ firstName: /SAM/}
returns data.
Question 1: How do you write LIKE CLAUSE with spring-data-mongo Criteria?
Question 2 : is that the right way to use or and and clause with criteria
Thanks for reading
Criteria.where("field").regex(pattern) should work
Since I don't have the ability add comments...
If you do a static import on Criteria, it will make your where clauses look a lot better.
Criteria orAddress = new Criteria().orOperator(where("addresses.city").is(null), where("addresses.city").regex(city, "i"));
I have a problem trying to delete an object with Entity Framework, I previously query the context to get a list of objects I need to delete, then one by one I call deleteobject
IQueryable result = context.CustomObjects.Where(t=>t.Property = something)
foreach (CustomObject customObj in result)
{
context.DeleteObject(customObj);
}
When I call DeleteObject EF executes a weird query, something like that:
exec sp_executesql N'SELECT
[Extent1].[Value1] AS [Value1],
[Extent1].[Value2] AS [Value2],
[Extent1].[Value3] AS [Value3],
FROM [CustomObject] AS [Extent1]
WHERE [Extent1].[ID] = #EntityKeyValue1',N'#EntityKeyValue1 int',#EntityKeyValue1=59
This query seems to search all the object with ID = something, but ID it is just part of the entity key that is indeed composed by 3 fields, so it attaches like n thousands items and make the process very slow, that is a behavior I can't understand, I always deleted object in this way and I have never had such a problem
can someone have an idea?
Thanks
You could be fetching mutiple objects as defined by your where query. Also for each object you fetch, you will be fetching all fields on the object CustomObject.
The query thats being executed is a select query so this confirms the above behaviour.
If you want better performance then I recommend that you do something like this:
var entityToDelete = new SomeEntity();
SomeEntity.PK = 12;
var context = new YourContextntities();
context.YourEntitites.Attach(entityToDelete);
context.YourEntitites.Remove(entityToDelete);
context.SaveChanges();
I want to limit the length of a column in an EF query, ala:
var query = from ce in entities.ContactEvents
.Include("Person")
.Include("Orders")
where ce.PersonID = personID
orderby ce.DateTimeContact descending
select new ContactEvent
{
ID = ce.ID,
DateTimeContact = ce.DateTimeContact,
Description = ce.Description.Substring(0, 500),
Orders = ce.Orders
};
The query fails because the EF can't project the complex type Orders.
The entity or complex type 'Model.ContactEvent' cannot be constructed in a LINQ to Entities query.
I've tried a few different ways to do the same thing such as use an explicit join in the LINQ expression but so far I always hit a snag populating the Orders collection in the select projection.
Any ideas on how I can construct my query? Ideally I don't even want to use a select projection but I'm assuming I need to in order to be able to limit the length of the description column returned from the database.
You cannot project to entity types. That is the limitation. If you want to return projection (calling select new) you must either return anonymous type or custom non entity type. If you want to return entity type you must always return whole column from linq-to-entities. You can try to trim the column after object is materialized by using:
var data = (from ce in entities.ContactEvents
.Include("Person")
.Include("Orders")
where ce.PersonID = personID
orderby ce.DateTimeContact descending
select ce)
.AsEnumerable()
.Select(e => new ContactEvent
{
ID = e.ID,
DateTimeContact = e.DateTimeContact,
Description = e.Description.Substring(0, 500),
Orders = e.Orders
});
I have not clearly issue during query using two criterials like Id and Other. I use a Repository storing some data like id,iso,value. I have created an index("_id","Iso") to performs queries but queries are only returning my cursor if i use only one criterial like _id, but is returning nothing if a use two (_id, Iso) (commented code).
Are the index affecting the response or the query method are failing?
use :v1.6.5 and C# official.
Sample.
//Getting Data
public List<BsonObject> Get_object(string ID, string Iso)
{
using (var helper = BsonHelper.Create())
{
//helper.Db.Repository.EnsureIndex("_Id","Iso");
var query = Query.EQ("_Id", ID);
//if (!String.IsNullOrEmpty(Iso))
// query = Query.And(query, Query.EQ("Iso", Iso));
var cursor = helper.Db.Repository.FindAs<BsonObject>(query);
return cursor.ToList();
}
}
Data:
{
"_id": "2345019",
"Iso": "UK",
"Data": "Some data"
}
After that I have Updated my data using Update.Set() methods. I can see the changed data using MongoView. The new data are correct but the query is always returning the sames olds values. To see these values i use a page that can eventually cached, but if add a timestamp at end are not changing anything, page is always returning the same olds data. Your comments are welcome, thanks.
I do not recall offhand how the C# driver creates indexes, but the shell command for creating an index is like this:
db.things.ensureIndex({j:1});
Notice the '1' which is like saying 'true'.
In your code, you have:
helper.Db.Repository.EnsureIndex("_Id","Iso");
Perhaps it should be:
helper.Db.Repository.EnsureIndex("_Id", 1);
helper.Db.Repository.EnsureIndex("Iso", 1);
It could also be related to the fact that you are creating indexes on "_Id" and the actual id field is called "_id" ... MongoDB is case sensitive.
Have a quick look through the index documentation: http://www.mongodb.org/display/DOCS/Indexes