Could I ask somebody show me the way how to declare the association between two entities 'Record' and 'DictionaryItem' if corresponded tables on the DB level are joined by such interesting rule:
FROM Records R LEFT OUTER JOIN DictionaryItems D
ON SUBSTRING(R.CompositeKey,3,8) = D.DictionaryItemId
P.S. I'm now working with POCO entities.
Linq-to-entities doesn't support Substring. You must either execute SQL directly by calling context.Database.SqlQuery<> or you must use Entity SQL - that would probably require converting DbContext to ObjectContext via IObjectContextAdapter, creating ObjectSet and running ESQL query.
Related
In an app with EF6.0, I have two DbContext's created by model first, Schema1.DbContext1 and Schema2.DbContext2.
Now I need to do a join on two entities, EntityA from Schema1.DbContext1 and EntityB from Schema2.DbContext2.
How can I do this?
Have you tried just doing it?
Something like:
var result = context1.EntityA.Join(context2.EntityB, a=>a.Key, b=>b.Key, (a,b)=>new {a,b});
I'm not sure how nice the SQL will be, since the join is done in LINQ. You'd want to test and see how it is actually being implemented!
If you can use stored procedures, this is a case for it. The proc can join the two entities at the database level across databases. Whichever db is appropriate, you can then map that proc in your entities model and use it. I say 'if you can' because I've seen shops that prohibit all SP's in favor of only EF.
I am using entity splitting to split properties across multiple tables - http://msdn.microsoft.com/en-us/data/jj591617
This adds an inner join to the resulting SQL query.
I expected this join would only be included when the query projection includes the properties in the secondary table. This is not the case when I use an anonymous type to isolate (project) a subset of needed fields. The resulting SQL query only selects columns from the base table but still includes the join.
Is there anyway to continue to use entity splitting and only include the join when necessary?
As far as I can tell, no. With Entity Framework, you can't lazy-load simple properties that are mapped to a column (which, in your case, would theoretically help you avoid the join); only navigation properties can be lazy-loaded. Perhaps you would need to employ table splitting instead to achieve the goal of eliminating the join.
For reference:
http://www.eidias.com/blog/2013/11/18/entity-framework-lazy-loading-properties
Ok, lets say you have two tables: Order and OrderLine and for some reason they do not have a foreign key relationship in the database (it's an example, live with it). Now, you want to join these two tables using Entity Framework and you cook up something like this:
using (var model = new Model())
{
var orders = from order in model.Order
join orderline in model.OrderLine on order.Id equals orderline.OrderId into orderlines
from ol in orderlines.DefaultIfEmpty()
select new {order = order, orderlines = orderlines};
}
Now, the above will produce orders and orderlines, left-joined and all, but it has numerous issues:
It's plain ugly
It returns an anonymous type
It returns multiple instances of the same order and I you have to do Distinct() on the client side because orders.Distinct() fails.
What I am looking for is a solution which is:
Pretty
Returns a statically well-known type instead of the anonymous type (I tried to project the query result, but I got into problems with the OrderLines)
Runs Distinct on the server side
Anyone?
Even if the database tables do not have a foreign key relationship setup, you can configure Entity Framework as if they do.
Add an OrderDetails navigation property to your Order class and then just query Orders.
I would like to create a query with CriteriaBuilder for this kind of sql;
SELECT myDefinedAlias.id, myDefinedAlias.name, myDefinedAlias.aFieldForFK select from Person as myDefinedAlias where myDefinedAlias.name = ?1
How can i accomplish defining an alias for this?
I can create queries without aliases but i cannot define aliases...
CriteriaQuery<Person> cq = criteriBuilder.createQuery(Person.class);
Root<Person> person = cq.from(Person.class);
cq = cq.select(person);
cq = cq.where(criteriaBuilder.equal(person.get(Person_.name), "Chivas")))
I need this for QueryHints, batch fetch.
.setHint(QueryHints.BATCH, "myDefinedAlias.aFieldForFK.itsNestedAttribute");
I am stuck and couldn't find anything regarding my problem. Anyone?
Regards
Doing cq.select(person).alias("myDefinedAlias") assigns your alias which can subsequently be used in batch/fetch query hints. Eclipselink supports nested fetch joins as long as you do not transfer to-Many relations (collections).
I.e..setHint(QueryHints.BATCH, myDefinedAlias.toOneRelation.toManyRelation") works while .setHint(QueryHints.BATCH, .setHint(QueryHints.BATCH, "myDefinedAlias.toManyRelation.toOneRelation") shouldn't.
I think you are going about this the wrong way. JPA needs the sql-statement-aliases for itself to use when generating sql-statements.
For the nested query hints to work, the relationship needs to be specified in the entities.
For example, if your Person entity have a OneToMany mapping to a House entity - and the property name in the Person class is livedInHouses. The query hint would become:
.setHint(QueryHints.BATCH, "Person.livedInHouses"). Its damn near impossible to use FKs that exists in the database but are not annotated as relations on/in entities in JPA.
I am using JPA2 with it's Criteria API to select my entities from the database. The implementation is OpenJPA on WebSphere Application Server. All my entities are modeled with Fetchtype=Lazy.
I select an entity with some criteria from the database and want to load all nested data from sub-tables at once.
If I have a datamodel where table A is joined oneToMany to table B, I can use a Fetch-clause in my criteria query:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<A> cq = cb.createQuery(A.class);
Root<A> root = cq.from(A.class);
Fetch<A,B> fetch = root.fetch(A_.elementsOfB, JoinType.LEFT);
This works fine. I get an element A and all of its elements of B are filled correctly.
Now table B has a oneToMany-relationship to table C and I want to load them too. So I add the following statement to my query:
Fetch<B,C> fetch2 = fetch.fetch(B_.elementsOfC, JoinType.LEFT);
But this wont do anything.
Does anybody know how to fetch multi level entities in one query?
It does not work with JPQL and there is no way to make it work in CriteriaQueries either. Specification limits fetched entities to the ones in that are referenced directly from the returned entity:
About fetch join with CriteriaQuery:
An association or attribute referenced by the fetch method must be
referenced from an entity or embeddable that is returned as the result
of the query.
About fetch join in JPQL:
The association referenced by the right side of the FETCH JOIN clause
must be an association or ele ment collection that is referenced from
an entity or embeddable that is returned as a result of the query.
Same limitation is also told in OpenJPA documentation.
For what is worth. I do this all the time and it works just fine.
Several points:
I'm using jpa 2.1, but I'm almost sure it used to work in jpa 2.0 as well.
I'm using the criteria api, and I know some things work diferent in jpql. So don't think it works some way or doesn't work because that's what happens in jpql. Most often they do behave in the same way, but not always.
(Also i'm using plain criteria api, no querydsl or anything. Sometimes it makes a difference)
My associations tend to be SINGULAR_ATTRIBUTE. So maybe that's the problem here. Try a test with the joins in reverse "c.fetch(b).fetch(a)" and see if that works. I know it's not the same, but just to see if it gives you any hint. I'm almost sure I have done it with onetomany left fetch joins too, though.
Yep. I just checked and found it: root.fetch("targets", LEFT).fetch("destinations", LEFT).fetch("internal", LEFT)
This has been working without problems for months, maybe more than a year.
I just run a test and it generates this query:
select -- all fields from all tables
...
from agreement a
left outer join target t on a.id = t.agreement_id
left outer join destination d on t.id = d.target_id
left outer join internal i on d.id = i.destination_id
And returns all rows with all associations with all fields.
Maybe the problem is a different thing. You just say "it wont do anyhting". I don't know if it throws an exception or what, but maybe it executes the query properly but doesn't return the rows you expect because of some conditions or something like that.
You could design a view in the DB joining tables b and c, create the entity and fetchit insted of the original entity.