I'm kinda stuggling with this being best practice or not..
I have a repository that returns an IQueryable lets say. Is this correct usage in the controller?
var whatever = ObjectRepository.GetWhatever(id);
var videoId = whatever.UsersInObject1InObjects2.First().Object.Video.ExternalVideoId;
Where in the 2nd line above ".Object" and ".Video" are references to tables that are related to "whatever" table.
Or should I be making another function in a different repository to get the ExternalVideoId?
The way I usually do this is this. I create a separate model class that encapsulates data that the controller need from the database. (I.e. as a rule I do not use ORM class for this). This allows me annotating the model class members with all sort of attributes I might need. In the repository code I query the ORM and then return the model class (or IQueryable/IEnumerbale of model) as the result.
I've heard an opinion that returning IQueryable from an ORM such as Entity Framework is not advised, because by doing this, you risk executing a query against your back end several times if you are not careful with your model in controller/view. This is because in EF IQueryable represent a query that is not executed yet. By returning IEnumerable instead of IQueryable you make sure that query execution is confined to your repository class.
I however find, that sometimes it's more convenient to return IQueryable. For example, for table paging/sorting scenarios I can apply page number, sort direction, page size, etc to the IQueryable before executing it. I feel that this logic belongs more to controller rather then to repository. Some may disagree.
What you're actually doing is using a collection to do a query.
I think you need to have a better look at linq queries.
You don't want to add custom queries to your repository.
You just want to expose the queryable interface like so..
public IQueryable<T> Get( IUser identity )
{
return Context.Set<T>();
}
public IQueryable<IBindable> GetItem( IUser identity )
{
return Context.Set<T>().Cast<IBindable>();
}
then you can use linq to sql
Related
I have a long-time burning question about how to avoid null errors with data queried via Entity Framework (version 6 - not Core yet, sadly).
Let's say you have a table Employees, and it has a relationship with another table, EmployeePayments (one employee has many employee payments).
On your Employee domain object you create a property TotalPayments which relies on you having loaded the EmployeePayments for that object.
I try to ensure that any time I do a query, I "include" the dependency, for example:
var employees = context.Employees.Include(e => e.EmployeePayments);
The problem is, I have a lot of queries around the place (I use the generic repository pattern, so I call repository functions like GetAll or GetSingle from my service library), and so that's a lot of places to remember to add the includes. If I don't include them, I run the risk of having a null exception if the TotalPayments property is used.
What's the best way to handle this?
Note 1: we have a lot of tables and I don't really want to have to revert to using specific repositories for each one, we take advantage of the generic repository in a lot of ways.... but I will be happy to hear strong arguments for the alternative :)
Note 2: I do not have lazy loading turned on, and don't plan on turning it on, for performance reasons.
This is one reason I consider the Generic Repository an anti-pattern for EF. I use a repository pattern, but scope it like I would a controller. I.e. a CreateOrderController would have a CreateOrderRepository. This repository would provide access to all relevant entities via IQueryable. Common stuff like lookups etc. would have their own secondary repository. Using generic repositories that are geared to working with a single entity type mean adding references to several repositories to do specific things and running into issues like this when attempting to load entities. Sometimes you want related data, sometimes you don't. Simply adding convenient methods in top level entities effectively "breaks" that an object should always be considered complete or complete-able without relying on lazy-loading which brings significant performance costs.
Having repositories return IQueryable avoids many of the problems by giving control to the calling code how entities are consumed. For instance I don't put helper methods in the entities, but rather code needing to populate a view model relies on Linq to build the view model. If my view model wants a sum of payments for an employee, then my repository returning IQueryable can do the following:
public IQueryable<Employee> GetEmployeeById(int employeeId)
{
return Context.Employees.Where(x => x.EmployeeId == employeeId);
}
then in the controller / service:
using (var contextScope = ContextScopeFactory.Create())
{
var employeeViewModel = EmployeeRepository.GetEmployeeById(employeeId)
.Select(x => new EmployeeSummaryViewModel
{
EmployeeId = x.EmployeeId,
EmployeeName = x.LastName + ", " + x.FirstName,
TotalPayments = x.Payments.Where(p => p.IsActive).Sum(p => p.Amount)
}).Single();
}
I use a repository because it is easier to mock out than the DbContext and it's DbSets. For Synchronous code I just have the mock to populate and return List<Employee>().AsQueryable(). For Async code I need to add a wrapper for an Async List.
This pattern may go against more traditional views of a repository and separation of concerns that the calling code needs to "know" about the entities, that EF-isms are leaked. However, no matter what approach you try to rationalize to get around the inefficiencies of trying to "hide" EF behind a repository, either you will be left with very inefficient code where repositories return pre-populated DTOs or contain dozens of near identical methods to return different DTOs (or worse, entities in various degrees of completeness) or you are adding complexities like passing in magic strings or expression trees into your methods to tell EF how to filter, how to sort, what to include, paging, etc. Passing in expressions or strings requires the calling code to "know" about the entities and leaks EF restrictions. (Passed in expressions / strings still have to be able to be ultimately understood by EF)
So this may not be a viable answer to the current state of your project, but it might be worth looking into whether your dependency on the repositories can be better managed without splitting them with the Generic pattern, and/or leveraging EF's excellent IQueryable / Linq capabilities to let your controllers/services project the entities into view models / DTOs rather than embedding these reduce elements in the entities themselves.
Following up on this question/answer
How to make Entity Framework Data Context Readonly
The solution is to make your DbContext collections of the type DbQuery, but that is a rather specialized type (it's buried down in the namespaces for EF).
So, what's the functional difference between have a DbContext with this:
public DbQuery<Customer> Customers
{
get { return Set<Customer>().AsNoTracking(); }
}
vs this:
public IQueryable<Customer> Customers
{
get { return Set<Customer>().AsNoTracking(); }
}
...the EF documentation is very light when it comes to the DbQuery class, but I prefer the idea of having DbContext made up of interfaces rather than classes so I'd like to avoid it. What additional benefits does the DbQuery class provide?
Update
After reading the answers and just looking at the code I realized my question was a little silly. I was too quick to ask before I thought! Obviously the underlying concrete object will be a DbQuery regardless, so the actually inner functionality will be the same. It seems to me that using IQueryable is the better choice. Thanks for your patience!
DBQuery is a non-generic LINQ to Entities query against a DbContext. Exposing this will give you LINQ functionality against Entities. If you don't need this, use the IQueryable interface abstraction.
IOrderedQueryable
Intended for implementation by query providers.
This interface represents the result of a sorting query that calls the method(s) OrderBy, OrderByDescending, ThenBy or ThenByDescending. When CreateQuery is called and passed an expression tree that represents a sorting query, the resulting IQueryable object must be of a type that implements IOrderedQueryable.
IListSource
Provides functionality to an object to return a list that can be bound to a data source.
IDbAsyncEnumerable
Asynchronous version of the IEnumerable interface that allows elements to be retrieved asynchronously. This interface is used to interact with Entity Framework queries and shouldn't be implemented by custom classes.
This is an old question, but it comes up in a google search on DbQuery, so just to update things a bit:
In EF Core 2.1, QueryTypes are now mapped to DbQuery types, as described in the documentation located at
https://learn.microsoft.com/en-us/ef/core/modeling/query-types
Here are the relevant bits:
Query types have many similarities with entity types...
...
However they are different from entity types in that they:
Do not require a key to be defined.
Are never tracked for changes on the DbContext and therefore are never inserted, updated or deleted on the database.
Are never discovered by convention.
Only support a subset of navigation mapping capabilities - Specifically:
They may never act as the principal end of a relationship.
They can only contain reference navigation properties pointing to entities.
Entities cannot contain navigation properties to query types.
Are addressed on the ModelBuilder using the Query method rather than the Entity method.
Are mapped on the DbContext through properties of type DbQuery rather than DbSet
Are mapped to database objects using the ToView method, rather than ToTable.
May be mapped to a defining query - A defining query is a secondary query declared in the model that acts a data source for a query type.
You define a QueryType in your DbContext like a DbSet, but using the DbQuery type:
public virtual DbQuery<CustomClassThatMapsYourQueryResults> QueryResults { get; set; }
Then in your OnModelCreating method you indicate that your custom results object is mapped to a stored proc in the database:
modelBuilder.Query<CustomClassThatMapsYourQueryResults>();
Then in your data access code somewhere:
var someVariable = 1;
var someOtherVariable = "someValue";
...
var myResults = _dbContext.FromSql($"spStoredProcName {someVariable} '{someOtherVariable}'");
As far as I know, the only way to populate the DbQuery< T > object is to use the FromSql() method. The DbQuery< T > results of the FromSql() method return IQueryable< T >.
I have inherited a code base that uses DTOs in the business layer, these are populated via a set of mappers from Entity Framework. This has some quite serious limitation in terms of querying so I am working on a new "optimised" querying service.
My first issue is that I need to translate my LINQ query on my DTO to work with my Entity object but the calling context has no knowledge of the EF entities. Let's assume we can rely on the properties on each object having matching names.
This is where I have got to in terms of stubbing out what I want:
public static List<TDataObject> GetFiltered<TDataObject(Expression<Func<TDataObject, TDataObject>> projection, Func<TDataObject, bool> filter)
{
// 1. translate the filter parameter to work with my equivalent Entity object
// 2. build the EF query with the modified filter expression and also a Select() projection so we only return the properties we need. (this should generate an optimised SQL query under the hood)
// 3. map the results from the EF query back onto my TDataObject and return (I already have AutoMapper maps in place for this)
}
It is item 1 that I am struggling with so if anyone has any code examples for blogs posts for achieving this I'd appreciate it.
Also if anyone has any alternate suggestions I'd be happy to hear them.
One way to handle this is to build primitives around queries (instead of layers with repositories etc). Here's what we do:
http://lostechies.com/jimmybogard/2013/10/29/put-your-controllers-on-a-diet-gets-and-queries/
The calling code (controller) knows about a query and the result (DTO), but the piece doing the mapping knows exactly about EF Context/NHibernate ISession. Works very well for us and keeps our controllers light and thin.
Alternatively, get rid of your layers, and expose the EF objects directly:
var dtos = context.Employees.Where(e => e.IsActive)
.Project().ToArray<EmployeeShowViewModel>();
Put this in the controller because who cares, layers and abstractions are productivity preventers and time wasters.
I am in the middle of rewriting legacy software to .Net and have created a Data Access Layer using Linq 2 SQL that is working pretty well. The database I am working with has over 230 tables and is not something I can really change. The problem I am running into is with the Business Layer. I would like for the developers to be able to query the business objects and have those queries map to the data layer. So something like Customers.Query(c=>c.ID=="MyID")
and have that be able to be passed to my DAL, context.CUSTOMERS.Query(c=>c.UID == "MyID")
I have generic Query methods in my DAL that will allow me to pass in the DAL query.
This is where I am stuck. I can create a method that uses an Expression but how do I get and then map those fields to the corresponding DAL fields and get the value that is trying to be matched. What I don't want is to have to expose the DAL objects to the end developers who are doing presentation layer stuff. I am open to ideas and suggestions.
Do the developers need to query the business objects using an expression? The reason I ask is because mapping expressions may be complicated. At some point, some mapping has to be done. The DAL is usually the mapping layer that turns DB objects into domain objects, and vice-versa.
Two other approaches to consider:
Use the repository pattern, where the caller passes in a query object. The DAL would be responsible for turning that query object into an expression. An example of the repository pattern is shown in a question that I asked.
Expose more specific methods, like:
public Customer GetCustomersById(int id) { ... }
I believe either of those two approaches would make things easier to query.
So I think I have been able to find a solution to this. Using ExpressionVisitor and help from this post
I modified the VisitMember method:
protected override Expression VisitMember(MemberExpression node)
{
string sDbField = ((SFWBusinessAttributes)node.Expression.Type.GetProperty(node.Member.Name).GetCustomAttribu`tes(typeof(SFWBusinessAttributes), true)[0]).DBColumn;
var expr = Visit(node.Expression);
if (expr.Type != node.Type)
{
MemberInfo newMember = expr.Type.GetMember(sDbField).Single();
return Expression.MakeMemberAccess(expr, newMember);
}
return base.VisitMember(node);
}
To pull the Attribute off of the Property of the Business Object.
To call everything I can do from the app:
BusObj.Query(a => a.IsDeleted != true && a.Company.Contains("Demo"))
Which calls a method in the business object
public List<Account> Query(Expression<Func<Account, bool>> expression)
{
using (Data.CustomerData data = new Data.CustomerData(_connstring))
{
return MapList(data.Query<Data.Database.ACCOUNT>(expression.Convert<Account, Data.Database.ACCOUNT>()).ToList());
}
Performance seems pretty good, I know there is going to be a hit with the mapping but it is something I can live with for now.
Disclaimer: I'm pretty new to DDD and its associated terminology, so if i'm mislabeling any concepts, please correct me.
I'm currently working on a site with a relatively simple domain model (Catalog items, each of which stores a collection of CatalogImage items.)
My repository follows the standard interface of FindbyID(int ID) GetAll() etc...
The problem arises when trying to find a particular image by its ID; I end up with methods such as FindImagebyID(int CatalogItemID, int ImgID)
As new requirments develop, and the object graph becomes more heavily nested, I could see an explosion of methods such as Find{NestedType}ByID(int catalogItemID,.....,int nestedTypeID)
Should I simply be returning an IEnumerable from the FindAll() method, and using Linq in a higher layer to form these queries? Or will that be a violation of SoC?
It sounds to me like you have a justification for building multiple repositories.
Example
interface CatalogRepository
{
Catalog FindByID(int ID);
}
interface CatalogImageRepository
{
CatalogImage FindByID(int ID);
}
This will properly separate out your concerns, since each repository is only responsible for knowing how to deal with that specific entity.
I would filter the model at a layer above the repository, with LINQ if you like. Makes the repository simple. If you are using LINQ to get the data from the database this method works very well, if you are having to use ADO or some other legacy data access layer than it might make it more difficult to make the repository so simple. Linq makes it easy so that you can have the repository return IQueryable and let the next layer add the filtering and the actual retrieval of data does not happen until it is asked for. This makes it possible to have a method on the repository like GetImages() that gets all images, and the next layer adds the filtering for a specific image. If you are using ADO, you are probably not going to want to bring back all images then filter....so could be a trade off.