Skip to content
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

Add API to configure construction of entity type instances #10789

Open
Tracked by #240
ajcvickers opened this issue Jan 27, 2018 · 10 comments
Open
Tracked by #240

Add API to configure construction of entity type instances #10789

ajcvickers opened this issue Jan 27, 2018 · 10 comments

Comments

@ajcvickers
Copy link
Contributor

Issue #10703 covered the ability of EF to call a parameterized constructor. However, the constructor to use is not configurable. This issue is about adding fluent API and/or annotations to do this and also:

  • How properties are bound
  • Injecting services or service methods--i.e. generalized case of ILazyLoader and its related delegate
  • Configuring a factory method instead of using a constructor directly
  • Consider NotMapped/Ignore to just exclude a constructor from being used by EF
@todd-skelton
Copy link

Is there any workaround to prevent parameterized constructors from being used until it's configurable? I have creation events in my constructors and they are getting raised every time the objects are queried.

@ajcvickers
Copy link
Contributor Author

@xKloc Starting with preview2, if there are both parameterized and empty constructors, then EF will choose the empty one. See #10852

@adrianiftode
Copy link

adrianiftode commented Feb 22, 2019

There is a note in the documentation of the Entity types with constructors section that as some point the following feature will be implemented:

As of EF Core 2.1, only services known by EF Core can be injected. Support for injecting application services is being considered for a future release.

Is this issue tracking this feature?

One of my use cases would be to have the ability to publish some interesting events that happen within an entity

public class Blog
{
    private readonly IMediator _mediator;
    private int _id;

    public Blog(string name, string author, IMediator mediator)
    {
        Name = name;
        Author = author;
        _mediator = mediator;
    }

    public async Task AddPost(string content)
    {
           this.Posts.Add(new Post(content));
           if (this.Posts.Count > PostsLimit)
           {
                 await _mediator.Publish(new MaximumBlogPostsReached(_id);
           }
    }
}

@thomasdc
Copy link

thomasdc commented Mar 5, 2020

Support for ctor injecting an ILogger in domain entities would be a great addition.

@AndriySvyryd
Copy link
Member

@ajcvickers
Copy link
Contributor Author

@AndriySvyryd Not sure it would be easy to do this with the API surface we have now. But it's a nice idea--maybe I'll add it as one of the built-in services we support.

@ajcvickers
Copy link
Contributor Author

@AndriySvyryd @thomasdc Filed #20203

@cesarsouza
Copy link

Wouldn't it be possible to allow injecting IServiceProvider and therefore make all services available to be grabbed by the entities?

Sure it sounds like a potential to apply many anti-patterns but the decision to use it could be left up to the user.

@frankbuckley
Copy link

Would love to see something like:

modelBuilder.Entity<Blog>().HasConstructor((string name, string author) => Blog.Create(name, author));

In the meantime, a NotMapped/Ignore attribute or a MappedConstructor attribute might be a quick win to avoid awkward workarounds for constructor selection.

@SetTrend
Copy link

SetTrend commented Oct 7, 2024

I'd like to propose a factory style plug-in implementation:

I suggest to add a new method to Microsoft.EntityFrameworkCore.DbContextOptionsBuilder, allowing to provide an alternative implementation for selecting an entity's appropriate constructor.

The proposed DbContextOptionsBuilder method may be defined like this:

public class DbContextOptionsBuilder : IDbContextOptionsBuilderInfrastructure
{
  ...
  public virtual DbContextOptionsBuilder UseConstructorFactory(IConstructorFactory constructorFactory);
}

The IConstructorFactory interface would specify a single method:

public interface IConstructorFactory
{
  IEntityFactory<TEntity> UseEntityFactory<TEntity>();
}

The IEntityFactory<TEntity> interface, in turn, would return a specific constructor per entity and current data row:

public interface IEntityFactory<out TEntity>
{
  public ConstructorInfo FindConstructor(DataRow dataRow);
  public TEntity InvokeConstructorAndInitializers(ConstructorInfo constructor, DataRow dataRow);
  public IEnumerable<TEntity> CreateObjects(DataTable dataTable);
}

(The above interface definition is based on System.Data for the sake of conciseness.)


I created a generic sample implementation of IEntityFactory<TEntity> here:

https://github.com/SetTrend/EFC-Constructor-MRE

My sample implementation comprises the following .NET Core 8.0 projects:

Project name Description
ConstructorFactoryInterfaces Definition of IConstructorFactory and IEntityFactory<TEntity> interfaces.
ConstructorFactory Sample implementations of IConstructorFactory and IEntityFactory<TEntity>, always choosing the most specific constructor.
ConstructorFactoryTests Unit tests, testing each of the class' methods.
Model Sample data model used for running the unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants