Reputation: 6804
I want to limit model that are returned by a navigational property. For example, I am using an AuditInfo
model to log the activity of a model. Once a model is deleted the DeletedBy
and Deleted
attributes are set. However since nothing is ever really "deleted" from the database, these models will still be populated in navigational properties referenced by other models.
AuditInfo Class
public class AuditInfo
{
[Key]
public int AuditInfoID { get; set; }
//Other attributes
public string DeletedBy { get; set; }
public DateTime? Deleted { get; set; }
}
Class that has a navigational properties
public class BlogPost
{
//Other attributes
//Only return Comment where Comment.AuditInfo.Deleted is NULL
public virtual IList<Comment> Comments { get; set; }
}
Class that is being audited
public class Comment
{
//Other attributes
public int AuditInfoID { get; set; }
}
How would I set up a constrain so that only the non-deleted comments (Comment.AuditInfo.Deleted is NULL) from a BlogPost.Comments?
Upvotes: 4
Views: 1830
Reputation: 177163
(I assume you are using EF Code-First, because of the [Key]
attribute.)
There are different ways to load navigation properties and related entities and you can apply a filter for some of these ways but not for all:
Lazy loading:
Your navigation property has to be virtual
so that lazy loading works at all:
public virtual IList<Comment> Comments { get; set; }
Loading the parent:
var blogPost = context.BlogPosts.Find(1);
foreach (var comment in blogPost.Comments) // lazy loading triggered here
{
}
You can't apply a filter here. Lazy loading will always load all comments of the given blog post.
Eager loading:
var blogPost = context.BlogPosts.Include(b => b.Comments)
.SingleOrDefault(b => b.Id == 1);
You can't apply a filter in Include
. Eager loading will always load all comments of the given blog post.
Explicit loading:
Loading the parent:
var blogPost = context.BlogPosts.Find(1);
You can apply a filter when you load the comments now:
context.Entry(blogPost).Collection(b => b.Comments).Query()
.Where(c => !c.AuditInfo.Deleted.HasValue)
.Load();
Projection:
You can apply a filter in the projected properties:
var blogPost = context.BlogPosts
.Where(b => b.Id == 1)
.Select(b => new
{
BlogPost = b,
Comments = b.Comments.Where(c => !c.AuditInfo.Deleted.HasValue)
})
.SingleOrDefault();
It is not possible to apply some kind of global filter policy in the model definition so that this filter gets applied for all methods above automatically and without specifying it explicitly in the explicit loading and in the projection example. (I think you have such a global model definition in mind, but that's not possible.)
Upvotes: 5
Reputation: 51504
Map the entity to a SQL View on that filters out the deleted entries.
Upvotes: 0
Reputation: 1576
maby add a custom property to entity class, which will use the navigation property but filter it and return filtered data?
Upvotes: 1