AndrewP
AndrewP

Reputation: 1618

Injecting dependencies into Entity Framework entities and projects

Is there a way to inject dependencies into objects returned from an EF Linq context.Entities.Select(x => new Y {...}) projection? (I am using Simple Injector, but concept remains)

Sort of thing I am trying to achieve: (this is just typed in, not compiled, sorry for any syntax errors/incompleteness)

// person MAY be an entity, but probably more likely a class to serve a purpose
public class Person {
  public string Name
  public DateTime DOB {get;set; }

  // what I want to achieve: note, I don't want to have complex logic in my model, I want to pass this out to a Service to determine.. obviously this example is over simplified...
  // this could be a method or a property with a get accessor
  public bool CanLegallyVote()  
  {
    return _someServiceThatWasInjected.IsVotingAge(this.DOB);
  }

  private readonly ISomeService _someServiceThatWasInjected;
  public Person (ISomeService service)
  {
    _someServiceThatWasInjected = service;
  }
}

// then calling code... I can't pass ISomeService into the "new Person", as "Additional information: Only parameterless constructors and initializers are supported in LINQ to Entities."

// If the above model represents a non-entity...
var person = context.People.Select(person => new Person {Name = x.Name, DOB = x.DateOfBirth}).First;
// OR, if the above model represents an EF entity...
var person = context.People.First();

if (person.CanLegallyVote()) {...}

// I don't want to invoke the service from the calling code, because some of these properties might chain together inside the model, I.e. I do not want to do the following:
if (_service.CanLegallyVote(person.DOB))

Are there any hooks in Linq / Entity Framework that would allow me to pass an object (via DI) to models created?

Upvotes: 2

Views: 1135

Answers (3)

Adam
Adam

Reputation: 1715

Ideally you don't want that in the entity itself since that is something you generally keep clean. You could do this with the repository pattern, which is an abstraction of your Person DbSet. The interface is generic and implementation is left up to the concrete type.

public interface IPersonRepository : IRepository<Person>
{
  ...
  public bool CanLegallyVote(Person person);
  public bool CanLegallyVote(int personId);
}

public class PersonRepository : IPersonRepository
{
  private readonly ISomeService _someService;
  public PersonRepository(ISomeService someService)
  {
    _someService = someService;
  }

  public bool CanLegallyVote(Person person)
  {
    return _someService.CanLegallyVote(person.DOB);
  }
  ...
}

You could also consider only having the property in a person DTO or viewmodel because it sounds like something that you want to display in your UI but is not stored in your database and therefore not part of your entity model. This gives you many more options to populate it (e.g. factory).

Upvotes: 0

Steven
Steven

Reputation: 172835

@Oryol is right, injecting application components into domain objects during construction is a bad idea, just like it is the other way around.

One solution is to use method injecting instead of constructor injection. This means that each domain method defines the services it requires as method arguments. For instance:

public bool CanLegallyVote(ISomeService service) { ... }

Upvotes: 5

oryol
oryol

Reputation: 5248

There is ObjectContext.ObjectMaterialized event. You can hook it. But in general injecting domain services into domain entities isn't good idea. You can find many articles on this subject.

Upvotes: 5

Related Questions