How to use the interception mechanism in Entity Framework 6.3? - c#

We need to add a new functionality in our app, such that for SELECT queries performed by our DbContext on its DbSets, for example when calling MyDbContext.Users, or MyDbContext.Students etc (User and Student inherit from a BaseEntity class, which includes a propery IsActive), we will be able to intercept them, check if the entity is of this base type BaseEntity, and modify the queries in some way, for example add a where clause to check if IsActive is true. I've tried to look into the IDbCommandInterceptor interface but its methods, including the one that is probably relevent to me, ReaderExecuting, intercept all kinds of SELECT statements performed on the database, not just the ones for the MyDbContext's dbsets.
How can I do this in the correct way?
Thanks, ashilon

Interceptors, in this instance, are probably not what you want. They intercept all queries for all DbContexts and you can only modify the SQL directly. This is too dangerous when you want to add a where clause because joins could mess everything up.
If you have a repository or some base class all queries go through, do it there. If you are always doing context.Students.Where(...) then there is a sneaky thing you can do, but not entirely sure if this'll work but I don't see why it wouldn't.
On your DbContext class, I would change all the DbSet property namesd, like Students, to StudentsDbSet. I would then add this property to replace it:
public IQueryable<Student> Students
{
get { return StudentdsDbSet.Where(a => a.IsActive); }
}
All old code would now refer to this property that forces IsActive only records. Then if you needed non-active students, you could do StudentsDbSet.Where(...) and you'd be good to go.

Related

How to use Find or Find<T> on DbContext in EF?

NB I'm not asking how to find/filter entities in the DB. I'm not asking about the difference between Find and Where. I'm not asking about the implication of generics.
According to the docs, the DbContext provides methods Find and Find<T>. Usually, I go through the DbSet but noticing that there's Add() on both the context directly and the DB set, I wanted to see what will happen if I try to filter directly on the context too, instead of the DB set.
I haven't found a single example of such call, though. A lot of information on going through the DB set and the differences mentioned in the disclaimer at the top. But I see no sample showing usage of Find() nor Find<T>() directly on the context.
Is it possible at all and if so, how? Intellisense is cryptic...
It does the same thing, but without using the DbSet. It works by specifying the type (entity) you want to fetch. You just have to specify the type, which must match your DbSet.
Is it possible at all and if so, how?
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options) { }
public DbSet<City> Cities{ get; set; }
public DbSet<State> States { get; set; }
}
And use it like so:
MyContext context = CreateContext() // Or inject it...
// Will return the City which have id == 5.
object myUntypedCity = context.Find(typeof(City), 5);
// Will return the city which have id == [your guid].
City myTypedCity = context.Find<City>(Guid.NewGuid());
As a sidenote; Add() on the Context works the same way. It will detect which type of entity it is and put it on the correct DbSet. I do not know what will happen if you have several DbSet using the same type.
why we have a non-generic Find() on the context given that quite a few
DBs are using integers for IDs, hence ensuring ambiguous ID values
between different entities/tables
In some scenarios you might not expose the DbSet or you only know the type of the entity. This can be very handy when making some very generic code where you don't have a typed entity nor know exactly what type of id (primary key) it has. It may be a Guid or an int. I myself have never found a practical use for Find on the DbContext.
When you use Find on a DbSet, the Type of entity is known, so it just needs to Find by the provided ID.
When you use Find on the DbContext, you either have to tell EF which Type (Entity) to find against from its known mappings, or you can use the Generic version which defines the Type of entity to search against.
Why would you use these methods instead of DbSet.Find? One example would be where you don't want to expose an aspect of your domain as a DbSet. For example if you have a DbSet of Customers, Businesses, etc. that all contain references to Address entities it would be uncommon to ever need to load an Address outside of that scope so you would probably opt not to expose a DbSet<Address> in your domain to potentially be abused through convenience. In the case where your DbContext actually does need to locate a particular Address, you could use DbContext.Find<Address>(addressId) to load it.
Honestly I don't use DbContext.Find(), I don't even use DbSet.Find(), I much, much prefer to work with IQueryable and projection. But hey, it's an option. :)

Entity Framework Code First: Is there a way to automatically filter disabled rows from DbSets?

In the data architecture I have to contend with, there are no deletes. Instead, all records have a nullable datetime2 that signals the record has been "disabled". This means that in the cases of direct selections on the entities, I'll always have to add in a check to see if the entity was disabled or not.
So far what I've come up with is just a simple extension method called .Enabled() that gets only the enabled rows. It seems effective so far, but it's also annoying that I have to type that in every case.
Surely someone else has skinned this cat before. Is there a better way to do this with Entity Framework I'm just not privy to?
I suppose you could do something like this
public class MyContext : DbContext
{
public IDbSet<Thing> Things { get; set; }
public IQueryable<Thing> EnabledThings
{
get
{
return Things.Where(t => t.Enabled);
}
}
}
or the same as an extension method (but on the context not the DbSet/queriable).
Personally in practice I actually do exactly as you have in your example and use Things.Enabled().Whatever
I don't know of anything native to Entity Framework. But normally when I run into this, I create an "repository" layer that I run most database transactions through. Then I create methods like GetAll() which returns all items with appropriate where statement in place to hide "deleted" items.

LINQ navigation properties in the MVC controller action?

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

Entity Framework Complex Type vs Creating new Entity

I'm reading about the Entity Framework 4.0 and I was wondering why should I create a complex type and not a new Entity (Table) and a relation between them?
The perfect example is an address. Using a complex type for an address is much easier to deal with than a new entity. With complex types you do not have to deal with the Primary Key. Think about accessing an address how many common types of entities would have an address (Business Units, People, Places). Imagine populating many peoples addresses and needing to set a key for each one. With complex types you simply access the internal properties of they type and you're done. Here is an MSDN link of an example. http://msdn.microsoft.com/en-us/library/bb738613.aspx
This question has been here a while already, but I'm going to add an answer anyway in the hopes that the next poor sob that comes along knows what he's in for.
Complex types do not support lazy loading, at least not in EF 4.3. Let's take the address situation as an example. You have a Person table with 15 columns, 5 of which contain address information for certain individuals. It has 50k records. You create entity Person for the table with a complex type Address.
If you need a list of names of all individuals in your database you would do
var records = context.Persons;
which also includes addresses, pumping 5*50k values into your list for no reason and with noticeable delay. You could opt to only load the values you need in an anonymous type with
var records = from p in context.Persons
select new {
LastName = p.LastName,
FirstName = p.FirstName,
}
which works well for this case, but if you needed a more comprehensive list with, say, 8 non-address columns you would either need to add each one in the anonymous type or just go with the first case and go back to loading useless address data.
Here's the thing about anonymous types: While they are very useful within a single method, they force you to use dynamic variables elsewhere in your class or class children, which negate some of Visual Studio's refactoring facilities and leave you open to run-time errors. Ideally you want to circulate entities among your methods, so those entities should carry as little baggage as possible. This is why lazy loading is so important.
When it comes to the above example, the address information should really be in a table of its own with a full blown entity covering it. As a side benefit, if your client asks for a second address for a person, you can add it to your model by simply adding an extra Address reference in Person.
If unlike the above example you actually need the address data in almost every query you make and really want to have those fields in the Person table, then simply add them to the Person entity. You won't have the neat Address prefix any more, but it's not exactly something to lose sleep over.
But wait, there's more!
Complex types are a special case, a bump on the smooth landscape of plain EF entities. The ones in your project may not be eligible to inherit from your entity base class, making it impossible to put them through methods dealing with your entities in general.
Assume that you have an entity base class named EntityModel which defines a property ID. This is the key for all your entity objects, so you can now create
class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel
which you then can use with Distinct() to filter duplicates from any IQueryable of type T where T is an entity class. A complex type can't inherit from EntityModel because it doesn't have an ID property, but that's fine because you wouldn't be using distinct on it anyway.
Further down the line you come across a situation where you need some way to go through any entity and perform an operation. Maybe you want to dynamically list the properties of an entity on the UI and let the user perform queries on them. So you build a class that you can instantiate for a particular type and have it take care of the whole thing:
public class GenericModelFilter<T> : where T : EntityModel
Oh wait, your complex type is not of type EntityModel. Now you have to complicate your entity inheritance tree to accommodate complex types or get rid of the EntityModel contract and reduce visibility.
Moving along, you add a method to your class that based on user selections can create an expression that you can use with linq to filter any entity class
Expression<Func<T, bool>> GetPredicate() { ... }
so now you can do something like this:
personFilter = new GenericModelFilter<Person>();
companyFilter = new GenericModelFilter<Company>();
addressFilter = new GenericModelFilter<Address>(); //Complex type for Person
...
var query = from p in context.Persons.Where(personFilter.GetPredicate())
join c in context.Companies.Where(companyFilter.GetPredicate()) on p.CompanyID = c.ID
select p;
This works the same for all entity objects... except Address with its special needs. You can't do a join for it like you did with Company. You can navigate to it from Person, but how do you apply that Expression on it and still end up with Person at the end? Now you have to take moment and figure out this special case for a simple system that works easily everywhere else.
This pattern repeats itself throughout the lifetime of a project. Do I speak from experience? I wish I didn't. Complex types keep stopping your progress, like a misbehaved student at the back of the class, without adding anything of essence. Do yourself a favor and opt for actual entity objects instead.
Based on Domain Driven Design Concepts, Aggregate root could have one or more internal objects as its parts. In this case, Internal objects - inside the boundary of Aggregate Root - does not have any KEY. The parent key will be applied to them or somehow like this. Your answer returns to the benefit of keeping all Parts inside Aggregate root that makes your model more robust and much simpler.

Inheritance and associations

I need to create a db structure where "Supplier" inherits from "Client". I used to have an association on Client that I want to move to Supplier, but I can figure out how to define this. IN VS When I add an association to Supplier I can only associate the fields explicitly defined in Supplier (And I need to associate Client.Id).
Can I use the workaround where I add ClientId in Supplier?
(updated)
Right; I see what you mean. I suspect that with LINQ-to-SQL you can only associate to the base-class, and it will give you the appropriate types. You can filter with OfType<T> etc.
You can't simply add the id to the derived class, as it needs to be resolvable by LINQ when examining query expressions - and a bespoke standalone property won't be.
However, I also recall that this is possible in EF (even if I don't like EF overly ;-p).

Categories