-
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
Support DI for contructors of POCO #3342
Comments
We currently don't support this, but it is one of the capabilities for flexible object mapping (#240) we will consider adding in the future. |
@divega thank you for answer =) |
This work is covered by #240 |
Reopening to prioritize separately from the main flexible mapping issue. |
Parts of issues #3342, #240, #10509, #3797 The main things here are: - Support for injecting values into parameterized entity constructors - Property values are injected if the parameter type and name matches - The current DbContext as DbContext or a derived DbContext type - A service from the internal or external service provider - A delegate to a method of a service - Use of the above to inject lazy loading capabilities into entities For lazy loading, either the ILazyLoader service can be injected directly, or a delegate can be injected if the entity class cannot take a dependency on the EF assembly--see the examples below. Currently all constructor injection is done by convention. Remaining work includes: - API/attributes to configure the constructor binding - Allow factory to be used instead of using the constructor directly. (Functional already, but no API or convention to configure it.) - Allow property injection for services - Configuration of which entities/properties should be lazy loaded and which should not ### Examples In this example EF will use the private constructor passing in values from the database when creating entity instances. (Note that it is assumed that _blogId has been configured as the key.) ```C# public class Blog { private int _blogId; // This constructor used by EF Core private Blog( int blogId, string title, int? monthlyRevenue) { _blogId = blogId; Title = title; MonthlyRevenue = monthlyRevenue; } public Blog( string title, int? monthlyRevenue = null) : this(0, title, monthlyRevenue) { } public string Title { get; } public int? MonthlyRevenue { get; set; } } ``` In this example, EF will inject the ILazyLoader instance, which is then used to enable lazy-loading on navigation properties. Note that the navigation properties must have backing fields and all access by EF will go through the backing fields to prevent EF triggering lazy loading itself. ```C# public class LazyBlog { private readonly ILazyLoader _loader; private ICollection<LazyPost> _lazyPosts = new List<LazyPost>(); public LazyBlog() { } private LazyBlog(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public ICollection<LazyPost> LazyPosts => _loader.Load(this, ref _lazyPosts); } public class LazyPost { private readonly ILazyLoader _loader; private LazyBlog _lazyBlog; public LazyPost() { } private LazyPost(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public LazyBlog LazyBlog { get => _loader.Load(this, ref _lazyBlog); set => _lazyBlog = value; } } ``` This example is the same as the last example, except EF is matching the delegate type and parameter name and injecting a delegate for the ILazyLoader.Load method so that the entity class does not need to reference the EF assembly. A small extension method can be included in the entity assembly to make it a bit easier to use the delegate. ```C# public class LazyPocoBlog { private readonly Action<object, string> _loader; private ICollection<LazyPocoPost> _lazyPocoPosts = new List<LazyPocoPost>(); public LazyPocoBlog() { } private LazyPocoBlog(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public ICollection<LazyPocoPost> LazyPocoPosts => _loader.Load(this, ref _lazyPocoPosts); } public class LazyPocoPost { private readonly Action<object, string> _loader; private LazyPocoBlog _lazyPocoBlog; public LazyPocoPost() { } private LazyPocoPost(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public LazyPocoBlog LazyPocoBlog { get => _loader.Load(this, ref _lazyPocoBlog); set => _lazyPocoBlog = value; } } public static class TestPocoLoadingExtensions { public static TRelated Load<TRelated>( this Action<object, string> loader, object entity, ref TRelated navigationField, [CallerMemberName] string navigationName = null) where TRelated : class { loader?.Invoke(entity, navigationName); return navigationField; } } ```
Parts of issues #3342, #240, #10509, #3797 The main things here are: - Support for injecting values into parameterized entity constructors - Property values are injected if the parameter type and name matches - The current DbContext as DbContext or a derived DbContext type - A service from the internal or external service provider - A delegate to a method of a service - Use of the above to inject lazy loading capabilities into entities For lazy loading, either the ILazyLoader service can be injected directly, or a delegate can be injected if the entity class cannot take a dependency on the EF assembly--see the examples below. Currently all constructor injection is done by convention. Remaining work includes: - API/attributes to configure the constructor binding - Allow factory to be used instead of using the constructor directly. (Functional already, but no API or convention to configure it.) - Allow property injection for services - Configuration of which entities/properties should be lazy loaded and which should not ### Examples In this example EF will use the private constructor passing in values from the database when creating entity instances. (Note that it is assumed that _blogId has been configured as the key.) ```C# public class Blog { private int _blogId; // This constructor used by EF Core private Blog( int blogId, string title, int? monthlyRevenue) { _blogId = blogId; Title = title; MonthlyRevenue = monthlyRevenue; } public Blog( string title, int? monthlyRevenue = null) : this(0, title, monthlyRevenue) { } public string Title { get; } public int? MonthlyRevenue { get; set; } } ``` In this example, EF will inject the ILazyLoader instance, which is then used to enable lazy-loading on navigation properties. Note that the navigation properties must have backing fields and all access by EF will go through the backing fields to prevent EF triggering lazy loading itself. ```C# public class LazyBlog { private readonly ILazyLoader _loader; private ICollection<LazyPost> _lazyPosts = new List<LazyPost>(); public LazyBlog() { } private LazyBlog(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public ICollection<LazyPost> LazyPosts => _loader.Load(this, ref _lazyPosts); } public class LazyPost { private readonly ILazyLoader _loader; private LazyBlog _lazyBlog; public LazyPost() { } private LazyPost(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public LazyBlog LazyBlog { get => _loader.Load(this, ref _lazyBlog); set => _lazyBlog = value; } } ``` This example is the same as the last example, except EF is matching the delegate type and parameter name and injecting a delegate for the ILazyLoader.Load method so that the entity class does not need to reference the EF assembly. A small extension method can be included in the entity assembly to make it a bit easier to use the delegate. ```C# public class LazyPocoBlog { private readonly Action<object, string> _loader; private ICollection<LazyPocoPost> _lazyPocoPosts = new List<LazyPocoPost>(); public LazyPocoBlog() { } private LazyPocoBlog(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public ICollection<LazyPocoPost> LazyPocoPosts => _loader.Load(this, ref _lazyPocoPosts); } public class LazyPocoPost { private readonly Action<object, string> _loader; private LazyPocoBlog _lazyPocoBlog; public LazyPocoPost() { } private LazyPocoPost(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public LazyPocoBlog LazyPocoBlog { get => _loader.Load(this, ref _lazyPocoBlog); set => _lazyPocoBlog = value; } } public static class TestPocoLoadingExtensions { public static TRelated Load<TRelated>( this Action<object, string> loader, object entity, ref TRelated navigationField, [CallerMemberName] string navigationName = null) where TRelated : class { loader?.Invoke(entity, navigationName); return navigationField; } } ```
Parts of issues #3342, #240, #10509, #3797 The main things here are: - Support for injecting values into parameterized entity constructors - Property values are injected if the parameter type and name matches - The current DbContext as DbContext or a derived DbContext type - A service from the internal or external service provider - A delegate to a method of a service - The IEntityType for the entity - Use of the above to inject lazy loading capabilities into entities For lazy loading, either the ILazyLoader service can be injected directly, or a delegate can be injected if the entity class cannot take a dependency on the EF assembly--see the examples below. Currently all constructor injection is done by convention. Remaining work includes: - API/attributes to configure the constructor binding - Allow factory to be used instead of using the constructor directly. (Functional already, but no API or convention to configure it.) - Allow property injection for services - Configuration of which entities/properties should be lazy loaded and which should not ### Examples In this example EF will use the private constructor passing in values from the database when creating entity instances. (Note that it is assumed that _blogId has been configured as the key.) ```C# public class Blog { private int _blogId; // This constructor used by EF Core private Blog( int blogId, string title, int? monthlyRevenue) { _blogId = blogId; Title = title; MonthlyRevenue = monthlyRevenue; } public Blog( string title, int? monthlyRevenue = null) : this(0, title, monthlyRevenue) { } public string Title { get; } public int? MonthlyRevenue { get; set; } } ``` In this example, EF will inject the ILazyLoader instance, which is then used to enable lazy-loading on navigation properties. Note that the navigation properties must have backing fields and all access by EF will go through the backing fields to prevent EF triggering lazy loading itself. ```C# public class LazyBlog { private readonly ILazyLoader _loader; private ICollection<LazyPost> _lazyPosts = new List<LazyPost>(); public LazyBlog() { } private LazyBlog(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public ICollection<LazyPost> LazyPosts => _loader.Load(this, ref _lazyPosts); } public class LazyPost { private readonly ILazyLoader _loader; private LazyBlog _lazyBlog; public LazyPost() { } private LazyPost(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public LazyBlog LazyBlog { get => _loader.Load(this, ref _lazyBlog); set => _lazyBlog = value; } } ``` This example is the same as the last example, except EF is matching the delegate type and parameter name and injecting a delegate for the ILazyLoader.Load method so that the entity class does not need to reference the EF assembly. A small extension method can be included in the entity assembly to make it a bit easier to use the delegate. ```C# public class LazyPocoBlog { private readonly Action<object, string> _loader; private ICollection<LazyPocoPost> _lazyPocoPosts = new List<LazyPocoPost>(); public LazyPocoBlog() { } private LazyPocoBlog(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public ICollection<LazyPocoPost> LazyPocoPosts => _loader.Load(this, ref _lazyPocoPosts); } public class LazyPocoPost { private readonly Action<object, string> _loader; private LazyPocoBlog _lazyPocoBlog; public LazyPocoPost() { } private LazyPocoPost(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public LazyPocoBlog LazyPocoBlog { get => _loader.Load(this, ref _lazyPocoBlog); set => _lazyPocoBlog = value; } } public static class TestPocoLoadingExtensions { public static TRelated Load<TRelated>( this Action<object, string> loader, object entity, ref TRelated navigationField, [CallerMemberName] string navigationName = null) where TRelated : class { loader?.Invoke(entity, navigationName); return navigationField; } } ```
Parts of issues #3342, #240, #10509, #3797 The main things here are: - Support for injecting values into parameterized entity constructors - Property values are injected if the parameter type and name matches - The current DbContext as DbContext or a derived DbContext type - A service from the internal or external service provider - A delegate to a method of a service - The IEntityType for the entity - Use of the above to inject lazy loading capabilities into entities For lazy loading, either the ILazyLoader service can be injected directly, or a delegate can be injected if the entity class cannot take a dependency on the EF assembly--see the examples below. Currently all constructor injection is done by convention. Remaining work includes: - API/attributes to configure the constructor binding - Allow factory to be used instead of using the constructor directly. (Functional already, but no API or convention to configure it.) - Allow property injection for services - Configuration of which entities/properties should be lazy loaded and which should not ### Examples In this example EF will use the private constructor passing in values from the database when creating entity instances. (Note that it is assumed that _blogId has been configured as the key.) ```C# public class Blog { private int _blogId; // This constructor used by EF Core private Blog( int blogId, string title, int? monthlyRevenue) { _blogId = blogId; Title = title; MonthlyRevenue = monthlyRevenue; } public Blog( string title, int? monthlyRevenue = null) : this(0, title, monthlyRevenue) { } public string Title { get; } public int? MonthlyRevenue { get; set; } } ``` In this example, EF will inject the ILazyLoader instance, which is then used to enable lazy-loading on navigation properties. Note that the navigation properties must have backing fields and all access by EF will go through the backing fields to prevent EF triggering lazy loading itself. ```C# public class LazyBlog { private readonly ILazyLoader _loader; private ICollection<LazyPost> _lazyPosts = new List<LazyPost>(); public LazyBlog() { } private LazyBlog(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public ICollection<LazyPost> LazyPosts => _loader.Load(this, ref _lazyPosts); } public class LazyPost { private readonly ILazyLoader _loader; private LazyBlog _lazyBlog; public LazyPost() { } private LazyPost(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public LazyBlog LazyBlog { get => _loader.Load(this, ref _lazyBlog); set => _lazyBlog = value; } } ``` This example is the same as the last example, except EF is matching the delegate type and parameter name and injecting a delegate for the ILazyLoader.Load method so that the entity class does not need to reference the EF assembly. A small extension method can be included in the entity assembly to make it a bit easier to use the delegate. ```C# public class LazyPocoBlog { private readonly Action<object, string> _loader; private ICollection<LazyPocoPost> _lazyPocoPosts = new List<LazyPocoPost>(); public LazyPocoBlog() { } private LazyPocoBlog(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public ICollection<LazyPocoPost> LazyPocoPosts => _loader.Load(this, ref _lazyPocoPosts); } public class LazyPocoPost { private readonly Action<object, string> _loader; private LazyPocoBlog _lazyPocoBlog; public LazyPocoPost() { } private LazyPocoPost(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public LazyPocoBlog LazyPocoBlog { get => _loader.Load(this, ref _lazyPocoBlog); set => _lazyPocoBlog = value; } } public static class TestPocoLoadingExtensions { public static TRelated Load<TRelated>( this Action<object, string> loader, object entity, ref TRelated navigationField, [CallerMemberName] string navigationName = null) where TRelated : class { loader?.Invoke(entity, navigationName); return navigationField; } } ```
Parts of issues #3342, #240, #10509, #3797 The main things here are: - Support for injecting values into parameterized entity constructors - Property values are injected if the parameter type and name matches - The current DbContext as DbContext or a derived DbContext type - A service from the internal or external service provider - A delegate to a method of a service - The IEntityType for the entity - Use of the above to inject lazy loading capabilities into entities For lazy loading, either the ILazyLoader service can be injected directly, or a delegate can be injected if the entity class cannot take a dependency on the EF assembly--see the examples below. Currently all constructor injection is done by convention. Remaining work includes: - API/attributes to configure the constructor binding - Allow factory to be used instead of using the constructor directly. (Functional already, but no API or convention to configure it.) - Allow property injection for services - Configuration of which entities/properties should be lazy loaded and which should not ### Examples In this example EF will use the private constructor passing in values from the database when creating entity instances. (Note that it is assumed that _blogId has been configured as the key.) ```C# public class Blog { private int _blogId; // This constructor used by EF Core private Blog( int blogId, string title, int? monthlyRevenue) { _blogId = blogId; Title = title; MonthlyRevenue = monthlyRevenue; } public Blog( string title, int? monthlyRevenue = null) : this(0, title, monthlyRevenue) { } public string Title { get; } public int? MonthlyRevenue { get; set; } } ``` In this example, EF will inject the ILazyLoader instance, which is then used to enable lazy-loading on navigation properties. Note that the navigation properties must have backing fields and all access by EF will go through the backing fields to prevent EF triggering lazy loading itself. ```C# public class LazyBlog { private readonly ILazyLoader _loader; private ICollection<LazyPost> _lazyPosts = new List<LazyPost>(); public LazyBlog() { } private LazyBlog(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public ICollection<LazyPost> LazyPosts => _loader.Load(this, ref _lazyPosts); } public class LazyPost { private readonly ILazyLoader _loader; private LazyBlog _lazyBlog; public LazyPost() { } private LazyPost(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public LazyBlog LazyBlog { get => _loader.Load(this, ref _lazyBlog); set => _lazyBlog = value; } } ``` This example is the same as the last example, except EF is matching the delegate type and parameter name and injecting a delegate for the ILazyLoader.Load method so that the entity class does not need to reference the EF assembly. A small extension method can be included in the entity assembly to make it a bit easier to use the delegate. ```C# public class LazyPocoBlog { private readonly Action<object, string> _loader; private ICollection<LazyPocoPost> _lazyPocoPosts = new List<LazyPocoPost>(); public LazyPocoBlog() { } private LazyPocoBlog(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public ICollection<LazyPocoPost> LazyPocoPosts => _loader.Load(this, ref _lazyPocoPosts); } public class LazyPocoPost { private readonly Action<object, string> _loader; private LazyPocoBlog _lazyPocoBlog; public LazyPocoPost() { } private LazyPocoPost(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public LazyPocoBlog LazyPocoBlog { get => _loader.Load(this, ref _lazyPocoBlog); set => _lazyPocoBlog = value; } } public static class TestPocoLoadingExtensions { public static TRelated Load<TRelated>( this Action<object, string> loader, object entity, ref TRelated navigationField, [CallerMemberName] string navigationName = null) where TRelated : class { loader?.Invoke(entity, navigationName); return navigationField; } } ```
Parts of issues #3342, #240, #10509, #3797 The main things here are: - Support for injecting values into parameterized entity constructors - Property values are injected if the parameter type and name matches - The current DbContext as DbContext or a derived DbContext type - A service from the internal or external service provider - A delegate to a method of a service - The IEntityType for the entity - Use of the above to inject lazy loading capabilities into entities For lazy loading, either the ILazyLoader service can be injected directly, or a delegate can be injected if the entity class cannot take a dependency on the EF assembly--see the examples below. Currently all constructor injection is done by convention. Remaining work includes: - API/attributes to configure the constructor binding - Allow factory to be used instead of using the constructor directly. (Functional already, but no API or convention to configure it.) - Allow property injection for services - Configuration of which entities/properties should be lazy loaded and which should not ### Examples In this example EF will use the private constructor passing in values from the database when creating entity instances. (Note that it is assumed that _blogId has been configured as the key.) ```C# public class Blog { private int _blogId; // This constructor used by EF Core private Blog( int blogId, string title, int? monthlyRevenue) { _blogId = blogId; Title = title; MonthlyRevenue = monthlyRevenue; } public Blog( string title, int? monthlyRevenue = null) : this(0, title, monthlyRevenue) { } public string Title { get; } public int? MonthlyRevenue { get; set; } } ``` In this example, EF will inject the ILazyLoader instance, which is then used to enable lazy-loading on navigation properties. Note that the navigation properties must have backing fields and all access by EF will go through the backing fields to prevent EF triggering lazy loading itself. ```C# public class LazyBlog { private readonly ILazyLoader _loader; private ICollection<LazyPost> _lazyPosts = new List<LazyPost>(); public LazyBlog() { } private LazyBlog(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public ICollection<LazyPost> LazyPosts => _loader.Load(this, ref _lazyPosts); } public class LazyPost { private readonly ILazyLoader _loader; private LazyBlog _lazyBlog; public LazyPost() { } private LazyPost(ILazyLoader loader) { _loader = loader; } public int Id { get; set; } public LazyBlog LazyBlog { get => _loader.Load(this, ref _lazyBlog); set => _lazyBlog = value; } } ``` This example is the same as the last example, except EF is matching the delegate type and parameter name and injecting a delegate for the ILazyLoader.Load method so that the entity class does not need to reference the EF assembly. A small extension method can be included in the entity assembly to make it a bit easier to use the delegate. ```C# public class LazyPocoBlog { private readonly Action<object, string> _loader; private ICollection<LazyPocoPost> _lazyPocoPosts = new List<LazyPocoPost>(); public LazyPocoBlog() { } private LazyPocoBlog(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public ICollection<LazyPocoPost> LazyPocoPosts => _loader.Load(this, ref _lazyPocoPosts); } public class LazyPocoPost { private readonly Action<object, string> _loader; private LazyPocoBlog _lazyPocoBlog; public LazyPocoPost() { } private LazyPocoPost(Action<object, string> lazyLoader) { _loader = lazyLoader; } public int Id { get; set; } public LazyPocoBlog LazyPocoBlog { get => _loader.Load(this, ref _lazyPocoBlog); set => _lazyPocoBlog = value; } } public static class TestPocoLoadingExtensions { public static TRelated Load<TRelated>( this Action<object, string> loader, object entity, ref TRelated navigationField, [CallerMemberName] string navigationName = null) where TRelated : class { loader?.Invoke(entity, navigationName); return navigationField; } } ```
Hi guys. What is the status of this issue? It looks that according to the roadmap (https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/features) it will not be implemented in EF Core 3.0. Will it? |
Some support for constructor injection was added in 2.1. |
@ajcvickers - What is pending in this issue? Should we track it differently? |
@bricelam @smitpatel This is actually about being able to inject services registered in the application D.I. container. We haven't implemented this yet. |
Related to #13540 |
Hello EF Development team.
I have a question about dependency injection.
Does EF looking for dependencies when materializing object from database in this manner ?
After loading and materializing from database DataContext(DataContext is inherited from DbContext) must injected in constructor.
Anything like this is possible now ?
The text was updated successfully, but these errors were encountered: