I have 4 tables
Student, Result, ResultDetail and Queue
Result and ResultDetails are related with ResultID as ForeignKey.
Student and Result are related with StudentID as ForeignKey
and Student can have 'N' number of results but will have only one active Result.
Queue and Student are related with StudentID.
Now using Entity Framework and Repository Pattern,
I want to
Perform ->
Queue q join Student s on q.StudentID = s.StudentID
join Result r on q.StudentId = r.StudentID
Join ResultDetail rd on t.ResultID = rd.ResultId where r.IsActive = 1
Could some one please help in achieving this with Repository Pattern?
Do we need to create 4 Repositories even though we have relations between tables.
Performance is also a criteria .
Thanks in Advance.
Could some one please help in achieving this with Repository Pattern?
Yes. Create a custom subtype of DbContext to serve as your Repository. Add a DbSet Property for each of your entity types. Also put Navigation Properties on your Entities so your query so you don't have to use join in LINQ.
Related
I am developing a web application using MVC4 with Entity framework 5.
I have created generic repository for accessing database with unit of work.
Having the below two repository,
CustomerRepository - Customer table
LibraryRepository - Library table
These two tables are not linked with each other( there is no foreign key relation ).
Want to write a query by combining these repository. Is possible to write a query by combining two different repository?
If yes, please let me know the way.
If your generic repositories expose an IQueryable method, you should be able to use a LINQ join to query both repositories:
var items = from c in customerRepository.AsQueryable()
join l in libraryRepository.AsQueryable() on c.SomeProperty equals l.SomeOtherProperty
select new { CustomerName = c.FirstName, LibraryName = l.Name };
There may be limitations to what the query can do, but I did a quick proof of concept on my own codebase between two separate repositories and it worked just fine (with the expected sql firing).
Update
It appears you are attempting two separate queries with a where clause-- I don't believe LINQ2Entities supports what you are attempting to do. Try updating your code to the following:
var customer = (
from cus in _customer.Query()
join lib in _library.Query()
on cus.LId equals lib.Id select cus
).ToList();
Where you are replacing the two 'from/where' queries with a 'join/on'.
trying to work out how to do LINQ to Entities query for a many to many relationship which has a junction with fields table.
Below are the Domains models (I am using View models, but keeping it simple for this example).
Student Domain model
StudentID (PK)
ICollection<StudentCourse> StudentCourses
StudentCourse Domain model
StudentCourseID (PK)
StudentID (FK)
CourseID (FK)
ForAdult
ForSeniour
Description
Course Domain model
CourseID (PK)
ICollection<StudentCourse> StudentCourses
Note:
Since the junction table (i.e. StudentCourse) contains fields other than the two foreign keys, EF will create an entity for this.
Lazy Loading
I've got this working for lazy loading. The Navigation properties have been declared with the 'virtual' keyword.
The Query way - works!
var student = (from s in context.Students
where s.StudentID == id
select s).SingleOrDefault<Student>()
The Method way - works!
Student student = context.Students.Find(id);
Projection
BUT, I would prefer to do this with projection, for performance reasons, i.e. less trips to the database.
I'm really stuck on how to write up the LINQ to Entities query to return 1 student with (1 or) many StudentCourses.
I don't understand thoroughly how the Entity should be shaped, if you know what I mean.
For example, I've tried:
var myvar = from s in context.Students
from sc in s.StudentCourses
where s.StudentID == id
select s
What I require is to return an entity of Student with a collection of StudentCourses which could then be assigned to a Student and passed to the View model, then to the View.
Really would appreciate any help, as I've spent alot of time trying to solve this.
Also as a side note, I'm using the SingleOrDefault() method to cast the results of the var (IQueryable I think) to type Student. Is this the preferred way to cast?
You can get EF to eagerly load the related entities by using the Include method.
So using your LINQ example:
var student = (from s in context.Students
where s.StudentID == id
select s).Include("StudentCourses").FirstOrDefault();
And using extension methods:
var student = context.Students.Include("StudentCourses").FirstOrDefault(id);
The Student instance that is returned will have the StudentCourses collection populated with related entities. This should invoke only one SQL query that joins the tables together.
To answer your aside question: I prefer to use FirstOrDefault most of the time as above. The difference is that SingleOrDefault will expect exactly one result and throws an exception otherwise, whereas FirstOrDefault will return null if a student is not found.
Also, as the cast to Student is implicit, you don't need the <Student> type parameter.
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.