-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom proxy generation for entities #14554
Comments
Putting this in 3.0 to review the internal code used and ensure that proxies can be created without depending on internal code. |
Re-opening this since we decided in #17159 to make the annotations needed internal again. |
Hey, i'm looking for the same functionality - Is this now possible? If yes can someone give me a hint where to start. |
@davidkraus The only issue here is that you may need to make use of some EF internal APIs, which could mean your proxy implementation breaks when we change those APIs. If that's something you can live with, then the best place to start is with the code for proxies in the this repo. I'd be interested to hear how it goes. |
@ajcvickers using internal APIs is fine since it is 'just' a feature to catch errors earlier. I gave it a shot and it seems to work - I copied the whole Proxy package (the 3.1.8 version, not the current one) into our Project and startet from there. The important changes i made are in the Code
To get it working i added an injection for |
@davidkraus I've been pondering what to say here. My experience of proxies has not been all that great, primarily for two reasons:
Now I'm not sayin that these are insurmountable issues, but it feels to me like introducing proxies in order to override and throw exceptions is probably not the correct trade-off. One thing that would be easier and not have these issues would be to inject the public class Blog
{
private readonly DbContext _context;
private ICollection<Post> _posts;
public Blog()
{
}
private Blog(DbContext context)
{
_context = context;
}
public int Id { get; set; }
public ICollection<Post> Posts
{
get
{
if (_context != null && !_context.Entry(this).Navigation(nameof(Posts)).IsLoaded)
{
throw new InvalidOperationException("Posts is not loaded.");
}
return _posts;
}
set => _posts = value;
}
}
public class Post
{
private readonly DbContext _context;
private Blog _blog;
public Post()
{
}
private Post(DbContext context)
{
_context = context;
}
public int Id { get; set; }
public Blog Blog
{
get
{
if (_context != null && !_context.Entry(this).Navigation(nameof(Blog)).IsLoaded)
{
throw new InvalidOperationException("Posts is not loaded.");
}
return _blog;
}
set => _blog = value;
}
} Note however, that this does put an EF dependency directly into your entity type. |
Part of #626 Part of #15911 Fixes #20135 Fixes #14554 Fixes #24902 This is the lowest level of materialization interception--it allows the actual constructor/factory binding to be changed, such that the expression tree for the compiled delegate is altered. Introduces singleton interceptors, which cannot be changed per context instance without re-building the internal service provider. (Note that we throw by default if this is abused and results in many service providers being created.) The use of this for proxies has two big advantages: - Proxy types are created lazily, which vastly improves model building time for big models with proxies. See #20135. - Proxies can now be used with the compiled model, since the proxy types are not compiled into the model. See
Part of #626 Part of #15911 Fixes #20135 Fixes #14554 Fixes #24902 This is the lowest level of materialization interception--it allows the actual constructor/factory binding to be changed, such that the expression tree for the compiled delegate is altered. Introduces singleton interceptors, which cannot be changed per context instance without re-building the internal service provider. (Note that we throw by default if this is abused and results in many service providers being created.) The use of this for proxies has two big advantages: - Proxy types are created lazily, which vastly improves model building time for big models with proxies. See #20135. - Proxies can now be used with the compiled model, since the proxy types are not compiled into the model. See
I would like to generate my own proxies for the entities returned by EF.
The particular feature I would like to be able to implement, is similar to the LazyLoading proxies. But instead of lazy loading, I want to throw exceptions when un-loaded navigational properties are accessed.
And example navigational path could be Blog => Post => Comment.
A method that takes a Post as an argument might not know if the Comments list was loaded by the query. So if the Comments property is accessed, I would want my proxy to throw an exception, if there was no
Include
for that relation in the query.Currently, the issue is that the property would just be null, which could be interpreted wrongly be the runtime code.
I looked at the LazyLoading implementation, but it seems most of the code required to do this is marked as "Internal, do not use", so I would suggest there was a supported way of doing this. (If there is, I could not find it, but would love to know)
The text was updated successfully, but these errors were encountered: