Dependency Injection of entities in DBContext of EF Core - entity-framework

I am new to EF.
Is it possible to inject entities in an EF context?
Taking the case from Microsoft documentation: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
Let's say, I have different implementations of blog. When it comes to properties that require persistence, they are the same and implement IBlog interface to reflect that.
How should I define BloggingContext to work with any of the blogs? I cannot use IBlog. DBSet would not accept an interface as a generic reference type to be used as entity type.
Do I have do define a base abstract class for my blogs in order to inject them in EF context? Is this the only way?

Related

Created a BasePOCO (which basically is similar to Entity Frameworks Database First EntityObject class)

At work, there is an application was developed using Entity Framework Database First approach. Therefore, our business entity classes are derived from Entity Framework Database First's EntityObject class.
Our team was to modify the application by moving from Entity Framework Database First approach to Entity Framework Code First approach.
However, we have to modify all out business entity classes that derive by modifying them in such a way that they Stop inheriting from the EntityObject class.
The problem is that we use a lot of EntityObject class's methods and other features in a lot of classes.
We were planning to create a BasePOCO class that will replace the Entity Frameworks Database First EntityObject class.
We would have to implement some methods in the BasePOCO class that would function in the same manner as some methods in the EntityObject class.
For example, we have the following line in a code file ( entity instance in the line of code below being of type EntityObject )
entity.GetType().GetProperty(firstFilter + _referenceKey);
we can replace it with (we have to implement methods that do something similar):
basePOCOEntityObject.GetType().GetProperty(firstFilter + _referenceKey);
I'm assuming there were probably many companies who moved from Entity Framework Database First approach to the Code First approach
Therefore, Has anyone already created something like out BasePOCO (which basically has a lot of functionalities that is similar to Entity Frameworks Database First EntityObject class)?
GetType() is not an EntityObject method. It's available on all objects.
EntityObject's methods mostly are replaced by methods on the DbContext.ChangeTracker. The main difference is that you have to have a DbContext object to call these methods. This can require some code restructuring.

Entity Framework using a pure POCO model

Is it possible in Entity Framework using Code First to create a domain model of pure POCOs that are totally ignorant of the Entity Framework?, i.e. don't decorate any classes or properties with any attributes and annotations related to the EF, and don't use virtual keyword to be able to support lazy loading.
Can I achieve this? or do I have to make two models one for persistence model and one for domain model to achieve this.

DbContext Multiple Inheritance

The design of EF forces developers to inherit the DbContext class. Some reusable libraries (such as ASP.NET Identity) typically provides its functionality using the same inheritance route, i.e. by providing the IdentityDbContext base-class.
But obviously this won't work if you have 2 such libraries, e.g. requiring you to inherit from IdentityDbContext and CmsDbContext at the same time, which is obviously impossible to do on .NET. The result that I want is to have an application-dbcontext that contains both the models from my identity module and my cms module (I won't be able to separate this to 2 dbcontexts since that would mean I will end up with multiple connections and transactions, and that my models can only reference to either identity or cms entities, but not both).
It's hard to believe that this question hasn't seemed to be asked around EF community, but this seems like a horrendously bad ORM design. Inheritance only lets you to have strictly linear modularisation. (As a comparison, in NHibernate, ISession and your Configuration are 2 separate things, therefore you can use discovery process to build up your mapping-configuration from different unrelated modules, without messing with my ISession and thus my db-connection/transactions).
So the question is, let's say you're a developer of a module that would like to register models into entity-framework (similar to ASP.NET identity module), you won't want to have a base DbContext that the consuming application must inherit, because it would prevent them from consuming other modules (e.g. ASP.NET identity's IdentityDbContext). So what are my options?
Is there any way to register models into a DbContext class without requiring to inherit from a DbContext? Is overriding OnModelCreating the only way to get access to a ModelBuilder?
I don't think your comparison is entirely fair. (Although I'm the first to admit that NHibernate beats EF in many areas).
With NHibernate, usually you load objects by some generic method in which you supply the type you want to load. You could create ISession implementations with hard-coded Query<T> (or QueryOver<T>) properties, like...
public Query<MyUser> Users { get; set; }
...and you'd have the same "problem" that you can't merge, or inherit from, two different implementations.
Likewise, you could work with EF by loading objects by using context.Set<T> only. You could even inject the configuration (sort of) by supplying EntityTypeConfiguration classes (as a list) in the context's constructor, storing them in a member variable and adding them to the model builder in the OnModelCreating override.
These specialized context classes, like IdentityDbContext, are offered to make life easier if they suit you. They have hard-coded DbSet properties (among others). The fact that you can't multiple inherit them is not a design flaw. It's just a (non-negotiable) language specification.
Choose the one that most closely serves your needs (propably CmsDbContext) and add other class mappings yourself.

Generic Repository and Leaky Abstraction

I am implementing a repository pattern. My main reasons for this:
To abstract client code away from persistence specifics (Entity Framework)
To support testability
Generic Repository or not?
The issue I have run into is whether I should have a generic repository or not. An IQueryable<T> Query() method would provide the calling code with means to construct specific queries. The issue here is that this is leaky abstraction - Entity Framework specifics are now leaking into my client code.
How would this effect unit testing? Would I still be able to Mock the ICustomerRepository with this implementation?
How would this effect swopping out my persistence layer? Like Azure Storage Tables or NHibernate.
Otherwise I would have to implement very specific query method on ICustomerRepository, such as GetIsActiveByFirstName() and GetIsActiveByDistrict(). I dislike this a lot as my repository classes are going to become jam-packed with different query methods. This system has hundreds of models and so there could be hundreds or even thousands of these methods to write and maintain.
You can have a relatively clean IRepository<T> by sticking to the pattern.
Data Access LAyer
reference to EF and Core project
Has Respository<T> : IRepository<T>
Option has IEFJunk declaration (Only if using multiple repositories)
Reference to Core
Respository is injected with Context (typically during instantiation)
Core
Interfaces that can be "Injected"
IRepository declaration. With no EF data type use.
NO reference to EF
So now code in Core you can refer to an IRepository<t>.
The implementing class can have EF specifics. But this can not be accessed from core!
so you can have IQueryable.
public interface IRepositoryBase<TPoco>{
IQueryable<TPoco> GetListQ(Expression<Func<TPoco, bool>> predicate);
//...
BUt if you decided you wanted to add
//...
// logically exposing IQueryable<T> Include<T>(this IQueryable<T> source, string path) from EF
IQueryable<TPoco> IncludeNAVProp(string navToInclude);
}
Then the Repository implementation
return Context.Set<TPoco>().Include(navToInclude);
requires the underlying provider to be EF. So now mocking is against an actual EF provider.
And unless you are careful, EF specific code. leaks out.
Indeed the interface IRepository that has the CONCEPT "include" can already be considered LEAKY.
Keeping EF specifics out of your Interfaces, is the key to avoiding the leaks.
And you can have 1 IRepository<t> and 1 Respository<t> and support 100s of tables

Table per hierarchy inheritance with POCO entities in Entity Framework 4

Our organization is looking to standardize on Entity Framework once v4 comes out. As a result, I am looking at what it would take to migrate our application that uses NHibernate for persistence to EF4 using POCO support. In a couple of places we use single table inheritance (also known as Table Per Hierarchy). I have been unable to get it to work using the following.
Payment (base class [should be abstract but having trouble there as well])
CreditCardPayment (concrete implementation)
ACHPayment (concrete implementation)
CheckPayment (concrete implementation)
Right now, I am mapping them with only the base class properties. All of these classes are in the same namespace. They have a discrimimator that is called PaymentTypeId in the database, so the Payment mapping has a condition of "When PaymentTypeId = 0". Each of the subclasses have the same condition with different values (i.e. CreditCardPayment = 1, etc.).
When I try to load each a list of all payments using DataContext.Payments.ToList() (DataContext inherits from ObjectContext) I am getting the following exception:
"Object mapping could not be found for Type with identity 'DataLayer.DataModel.CreditCardPayment'."
I can't figure out what this means, as the POCO CreditCardPayment class lives in the same namespace as the POCO Payment class does (in fact in the same file).
What am I missing?
This is complaining not about database mapping, but model to CLR mapping.
The EF can't for some reason find your CreditCardPayment class.
Now one possible reason is that you haven't loaded the metadata for it yet.
For example if you have this:
Assembly 1:
- Payment
Assembly 2 references Assembly 1:
- CreditCardPayment extends Payment
Then when you query the EF doesn't know where CreditCardPayment lives.
The way to get around this is with LoadAssembly i.e:
using (DataContext ctx = new DataContext())
{
ctx.MetadataWorkspace.LoadFromAssembly(typeof(CreditCardPayment).Assembly);
// now do your query.
}
You need to tell to LoadFromAssembly every assembly that isn't directly reference by your DataContext class.
Note: typeof(Payment).Assembly is directly referenced because of the IQueryable<Payment> Payments property.
Hope this helps
Alex
Microsoft.
What I didn't represent before (I didn't think it relevant, but it was). Was that CreditCardPayment inherited from an intermediary class named "CreditPayment" and ACHPayment inherited from CashPayment. CreditCardPayment and CashPayment live in the same namespace and file, but were not represented in the EF mapping. Once I added those within the mapping file, everything worked ok.
So, even thought EF does not ever map to one of those types directly, it seems to need to know about them, because it changes the basetype of the CreditCardPayment classes et al. Thank you for your help on this.