I have an entity that I need to return only records where a given field value is greater than zero. I have seen examples of conditional mapping in the edmx and that seems like what I am in need of. However, my project is in EF 4.1 code first.
Is there not a way to do this using the code first approach?
I dont think there is an inbuilt method for achieving this, you can however expose a property in your DbContext in which you apply filtering, initially this will be readonly but i dont see a reason why you shouldnt be able to create your own DbSet implementation reflecting back to another DbSet (ProxyDbSet)
Readonly example:
class MyDbContext : DbContext
{
public IDbSet<User> Users { get; set; }
public IQueryable<User> Admins
{
get
{
return from user in users
where user.Role == "admin"
select user;
}
}
}
Related
I'm using Autofac and EF6.
I have a service which I would like to use with dbContext or with local collection. I've already tried to use InMemoryDatabase and inject it in a service, but I need to load all related entites due to validation rules and it'll lead to performance issues.
Is any way to solve this issue without creating the same service, but for local store (in such way I'll need to edit the logic in both of them and can lead to different behaviour)?
The goal of this is to preload in some cases all data and use local store, accessing multiple times to db context cause low performance.
Example of service:
public class ProductServiceDb {
private readonly IDbContext _db;
public ProductServiceDb(IDbContext db) {
_db = db;
}
public List<Product> GetAvailable()
{
return _db.Products.Where(_=>_.InStock).AsNoTracking().ToList();
}
}
public class ProductServiceLocal {
public List<Product> Products {get; set;}
public List<Product> GetAvailable()
{
return Products.Where(_=>_.InStock).ToList();
}
}
Also I've already thought about local data, but in such way I need to check in all methods if it's local data and use Local property then.
I once made this little extension method to tell EF that I'd prefer to get data from its cache:
public static IEnumerable<TEntity> PreferLocal<TEntity>(this DbSet<TEntity> dbSet,
Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
var func = predicate.Compile();
return dbSet.Local.Any(func) ? dbSet.Local.Where(func) : dbSet.Where(predicate);
}
As you see, if there's no data that meets the given predicate then EF tries to get it from the database.
I use this function in more complex business logic when I know that some entities will have to be addressed more than once, while it's not always clear when they will be fetched for the first time.
A caveat: it works well the way I use it, but it may fail badly if you rely on navigation properties being populated fully. When, for example, you first fetch a couple of products based on some predicate and then order lines, not all order lines may have a orderLine.Product property populated. Also, if lazy loading is enabled, EF will still query the database when collection navigation properties are addressed.
I have a project that is using Entity framework and AspNet Identity.
One of the parameters of the IdentityUser is a deactivated field.
Within the app, if I wanted to get the users, I would do this:
var users = Context.Users //etc....
However, I do not want this query to return any deactivated users. I know I could do this
var users = Context.Users.Where(x => x.Deactivated != true);
However, I am reluctant to do this, as I am sure that in time someone will forget to add this where clause.
Is there a way for entity to do this automatically to all context queries? I have found this:
https://learn.microsoft.com/en-us/ef/core/querying/filters
But I do not have EF core and cannot upgrade to it.
I know I could make a wrapper function and call this, but I am trying to find a better solution...
I often use a combination of XXXStore members and XXX members where the XXXStore is the DBSet and the XXX is a query with AsNoTracking(). I then use the XXX members in queries responding to GETs and the XXXStore only when I want to update the database. E.g.
public DbSet<User> UserStore { get; set; }
public IQueryable<User> Users => UserStore.AsNoTracking();
This gives the advantage of not tracking entities that won't be updated, but with a DRY approach that means not adding the AsNoTracking() verbosely all over the place.
This approach can easily be combined with a where clause:
public DbSet<User> UserStore { get; set; }
public IQueryable<User> Users => UserStore.AsNoTracking().Where(u => !u.Deactivated);
Filters can also work, but an advantage to this approach is that it's easy to make an exception when you really do need to access a deactivated user, too.
You can use Global Filters:
protected override void OnModelCreating(ModelBuilder modelBuilder){
modelBuilder.Entity<Blog>().Property<string>("TenantId").HasField("_tenantId");
// Configure entity filters
modelBuilder.Entity<Blog>().HasQueryFilter(b => EF.Property<string>(b, "TenantId") == _tenantId);
modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);
}
In the entity designer I set the conditional mapping on an entity where it filters all customers by an 'isactive' field.
That works great no problem with that, but the problem comes in my linq.
What happens when I need to set a customer to 'IsActive=false'. The property isn't mapped to my entity because the condition is mapped, but in Linq I can't find a way to change that.
using (var db = new CustDbConn())
{
Customer customer= db.Customers.Single(p => p.Id == idFromEmail);
customer.IsActive = false; //<----NOT FOUND, can not resolve 'isActive'
}
There has to be a way to access and change the conditions in LINQ, can someone shed some light on this? I thought about bypassing the model and just updating it using SqlCommand, but I shouldn't have to go through all that.
You can't change model (that's you're trying to do) using LINQ query.
The only way to manipulate IsActive property is to bring it into Customer model, and throw away conditional mapping.
UPD.
You're misunderstanding the main purpose of conditional mapping - inheritance.
Note, that using EF you don't work with database tables, you work with entity types. All you have, is a model. If any table field is missing from model, than yes, you can't access it via model. With reference to your question, yes, you can't change patients activity status, because there's no activity status in the model.
And yes, if you plan to use some sort of deletion/activity marker (like IsActive in you sample), you have to include it in your queries, otherwise you'll get inactive/deleted items in results. Of course, you can make helper/repository/wrapper/etc to automate it:
interface IEntity
{
int Id { get; }
bool IsActive { get; set; }
}
interface IRepository<T>
where T : IEntity
{
IQueryable<T> Get(bool includeInactiveEntities = false);
}
Currently I have a nice model, and I can generate a database based on that, but from what I can tell, the tables are never created (leading to all sorts of fun runtime errors).
My understanding is that there are three options for code first that would force EF to create the tables for me:
DropCreateDatabaseAlways
CreateDatabaseIfNotExists
DropCreateDatabaseIfModelChanges
How can I use these if I am doing things model first?
Additionally, is this an expected error, or when I selected generate database from model the first time is this supposed to happen automatically?
Edit: I tried calling
context.Database.Initialize(true);
context.Database.CreateIfNotExists();
and nothing changes.
also this is good toturial
tutorial
but if you made the model good the first time you access the dbContext the db should be created by the db strategy which you can set: Database.SetInitializer()
set initializer
in short after you create your model you need to create class that inherit from DbContext:
public class CompanyContext : DbContext
{
public CompanyContext() : base("CompanyDatabase") { }
public DbSet<Collaborator> Collaborators { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Manager> Managers { get; set; }
}
and then when you access this context the tables should be generated.
you can also seed the database with data you should inherit from the strategy you want to implement look at this link seeding database
I'm working on a record-level security system for a LINQ-to-SQL app. I currently have a wrapper around the DataContext's GetTable method that joins T to a user cross-reference table. T is any class that implements my ISecurable interface:
public interface ISecurable
{
bool CanRead { get; set; }
bool CanUpdate { get; set; }
bool CanDelete { get; set; }
}
My base repository class performs the join and updates each story's CanRead, CanUpdate, and CanDelete properties for the specified user:
var storiesVisibleToUser = repository.Get<Story>( user );
I'd like to replace the wrapper with an extension method, so I can do something like this:
var storiesVisibleToUser = repository.Get<Story>().ApplySecurity( user );
It's a subtle change, but will greatly decrease the coupling between the security code and the general data access code, so it will give me more flexibility for adding stuff like group-level security.
The problem is that the ApplySecurity extension method doesn't have access to the original DataContext, so it can't use GetTable<> to retrieve the cross-reference records.
Two questions:
Is there any way to get an IQueryable's DataContext, short of subclassing/wrapping it and passing the context in to the constructor?
Is an extension method the "proper" way to do this, or should I stick with a method in my repository that would have access to the original context?
One possible solution is to create an association between the Story and the cross-reference table. That then makes the other table available to Story queries without needing a reference to the original context.