Include properties passing a string parameter - asp.net-core

In ef6 using system.data.entity you could dynamically construct .Include queries as follows (very useful in a generic repository)
IQueryable<TEntity> query = dbSet; //some instance of DbSet<TEntity>
query = query.Include("OrderItems");
However microsoft.data.entity as of ef7 RC1 doesn't have a .Include extension method that supports that. Is there another way to achieve this?
A generic repository without the ability to load related entities through navigation properties is not very useful.

Related

ASP.Net Core Open Partial Generic Dependency Injection

I would like to register the following items for DI using an open generic implementation and interface. I know the following example will not work, as well as other combinations I've tried with MakeGenericType, or GetGenericArguments. I would like to simply call AddRepository<MyDbContext> and then be able to inject my implementation into classes without explicitly having to register the type I am using.
Interface
public interface IRepository<TEntity>
{
}
Implementation
public class Repository<TEntity, TContext> : IRepository<TEntity>
where TEntity : class
where TContext : DbContext
{
}
Registration
public static class RepositoryServiceCollectionExtensions
{
public static IServiceCollection AddRepository<TContext>(
this IServiceCollection services) where TContext : DbContext
{
services.TryAddScoped(
typeof(IRepository<>),
typeof(Repository< , TContext>));
return services;
}
}
The dependency injection container Microsoft.Extensions.DependencyInjection and its abstraction layer does not support open generic factories. So you generally cannot achieve what you would like to do there. There’s also no support planned.
Unlike many those other dependency injection related features, this is also not really possible to patch by just providing the right wrapper or factory types. So you will actually have to change your design here.
Since you want to resolve IRepository<TEntity> and the only way to do this is by registering an equivalent open generic type, you will have to have some type Repository<TEntity> that implements your repository. That makes it impossible to retrieve the database context type from the generic type argument, so you will have to use a different way here.
You have different options to do that. For example, you could configure your Repository<TEntity> (e.g. using M.E.Options) with the context type and make that resolve the Repository<TEntity, TContext> dynamically. But since you have actual control over your database context, I would suggest either adding a marker interface or introducing another type for the context which you can then register with the container:
public class Repository<TEntity> : IRepository<TEntity>
{
public Repository(IDbContext dbContextFactory)
{ … }
}
public class MyDbContext : DbContext, IDbContext
{ … }
Then, your extension method could look like this:
public static IServiceCollection AddRepository<TContext>(this IServiceCollection services)
where TContext : DbContext, IDbContext
{
services.AddTransient(typeof(IDbContext), sp => sp.GetService<TContext>());
services.TryAddScoped(typeof(IRepository<>), typeof(Repository<>));
return services;
}
Of course, this changes how your Repository implementation works, but I don’t actually assume that you need to know the TContext type other than to inject the database context type. So this will probably still work for you.
That being said, I have too agree with Chris Pratt, that you probably don’t need this. You say that you want to introduce the repository, because “coding stores and implementations for every entity is a time consuming task” but you should really think about whether you actually need that. A generic repository is very limited in what it can do, and mostly means that you are doing just CRUD operations. But exactly that is what DbContext and DbSet<T> already do:
C: DbContext.Add, DbSet<T>.Add
R: DbContext.Find, DbSet<T>.Find
U: DbContext.Update, DbSet<T>.Update
D: DbContext.Remove, DbSet<T>.Remove
In addition, DbContext is a “unit of work” and DbSet<T> is an IQueryable<T> which gives you a lot more control and power than a generic repository could possible give you.
You cannot have a partially open generic reference. It's all or nothing. In other words, you can try:
services.TryAddScoped(
typeof(IRepository<>),
typeof(Repository<,>));
But, if that doesn't work, you'll likely need to add a type param to your AddRepository method:
public static IServiceCollection AddRepository<TEntity, TContext>(this IServiceCollection services)
where TEntity : class
where TContext : DbContext
{
services.TryAddScoped(
typeof(IRepository<TEntity>),
typeof(Repository<TEntity, TContext>));
return services;
}
Of course, I think that breaks what you're ultimately trying to achieve here: registering repositories for all the entity types in one go. You can always use a bit of reflection find all entities in your assembly (they would need to share something in common: base class, interface, etc.) and then enumerate over them and use reflection to call AddScoped on your service collection for each.
All that said, the best thing you can do here is to actually throw all this away. You don't need the repositories. EF already implements the repository and unit of work patterns. When you use an ORM like EF, you're essentially making that your data layer instead of a custom class library you create. Putting you own custom wrapper around EF not only adds entropy to your code (more to maintain, more to test, and more than can break), but it can also mess up the way EF works in many cases, leading to less efficiency in the best cases and outright introducing bugs into your application in the worst cases.

ICriteriaQuery not supporting AddUsedTypedValues with higher version of NHibernate

In older version of NHibernate there was a method called "AddUsedTypedValues" in ICriteriaQuery. After upgrading to NHibernate 3.1, such a method does not exist. Does anyone know where was that method moved (to another interface) or NHibernate removed support for it explicitly?
Thanks!
Method AddUsedTypedValues was replaced as well as the (AbstractCriterion : )ICriterion internal implementation. AddUsedTypedValues was a way how to inject parameters and they were later called inside ICriterion implementer like sqlStringBuilder.AddParameter(); (so the distance from Adding and usage was significant and not explicit)
Current versions (3+) provides ICriteriaQuery method
IEnumerable NewQueryParameter(TypedValue parameter);
which can be used to get an array of Parameters and then explicitly used when SQL statement is built:
var parameter = criteriaQuery.NewQueryParameter(typedValue).Last()
sqlStringBuilder.Add(parameter);
And now it is clear which parameter is added to a SQL statement. I had to implement my own ICrietrion, so I faced that issue as well...

How to set NHibernate Linq fetch strategy through a façade layer

I’m using NHibernate for data access, but accessing it through a façade layer. This layer consists of interfaces for the repositories, plus an IUnitOfWork interface which corresponds to the ISession object.
In order that retrieved entities are managed correctly, repositories are passed an IUnitOfWork in their constructor and the IUnitOfWork is used for the loading.
The IUnitOfWork contains a property called All, which retrieves all entities of the class as an IQueryable (for later filtering). Thus, a repository method to retrieve all entities created this year might look like the following:
NB: this is not the complete code for these interfaces and classes! Only the code relevant to my question.
IUnitOfWork interface:
IQueryable<T> GetList<T>();
UnitOfWork concrete class:
public IQueryable<T> GetList<T>()
{
return _session.Linq<T>();
}
IFooRepository interface
IQueryable<Foo> All { get; }
IEnumerable<Foo> ThisYearsFoos{ get; }
FooRepository concrete class
public IQueryable<Foo> All
{
get { return _unitOfWork.GetList<Foo>(); }
}
public IEnumerable<Foo> ThisYearsFoos
{
get { return All.Where(x => x.DateCreated > new DateTime(2010,1,1);}
}
I would like to add functionality to specify fetch strategies so that related entities can be eagerly loaded. So let’s say Foo has a property corresponding to another entity, Bar:
public class Foo
{
public Bar {get;set;}
}
The mapping file specifies that Bar is lazy-loaded, but in my ThisYearsFoos repository property I would like to specify that Bar should be eagerly loaded to avoid N+1 selects.
In Linq to NHibernate we can specify eager fetching using the Expand() extension method. However, this extension method belongs to the NHibernateQueryable type, whereas the IUnitOfWork interface’s GetList method only knows about IQueryable.
Clearly I don’t want the IUnitOfWork interface to know about INHibernateQueryable since it is supposed to not know about NHibernate.
Using the design I have specified above, is there a way to do this that I haven’t been able to think of? Or is my design in need of a rethink?
Thanks
David
Upgrade to NHibernate 3.x. The new method that corresponds to Expand (Fetch) operates on IQueryable.
You are saying some conflicting things:
- You don't want to expose interface
- You want to use the use that interface
That is impossible. You have to rethink your design.
You use the term unit of work for a different thing than most people do.
Most people would expect a unit of work interface to have the methods Commit and RollBack, but not some IQueryable.

FluentNhibernate dynamic runtime mappings

I am building a framework where people will be able to save items that the created by inheriting a class of mine. I will be iterating over every type in the appdomain to find classes that I want to map to nhibernate. Every class that I find will be a subclass of the inherited type.
I know how to create sub types in FluentNhibernate, but every sub type requires its own ClassMap class. Since I won't know these untill runtime, there is no way I can do that.
Is there a way that I can add mappings to fluent nhibernate?
Note, I know this is possible without fluent nhibernate using the Cfg class, but I don't want to manage the same code two different ways.
something along the lines
Type classToMap = GetClassToMap();
var subclassmap = typeof(SubClassMap<>).MakeGenericType(classToMap);
foreach(var item in classToMap.GetPropertiesToMapSomehow())
{
var expression = // build lambda of property
subclassMap.Map(expression).Column("col") ...
}
config.Add(subclassmap) // NHibernate.Cfg.Configuration
There was support for this at once time, and the api is still there, but it is now depricated.

Applying Spring .Net Advice to HibernateTemplate object

I have an class for auditing:
public class AuditAfterAdvise : IAfterReturningAdvice
This is applied to a Dao class in my Spring.Net configuration, using a RegularExpressionMethodPointcutAdvisor.
The Dao class implementation calls HibernateTemplate.SaveOrUpdate(object entity) to commit changes.
I would like to be able to apply AuditAfterAdvise class to the HibernateTemplate SaveOrUpdate() method used in my Dao, rather than the methods on the Dao itself.
The NHibenate/Spring setup is to use a LocalSessionFactoryObject for the Dao. Is this possible?
Thanks.
It certainly should be possible.
Instead of configuring the Dao, add the advice to the object definition for the LocalSessionFactoryObject. The RegularExpressionPointCutAdvisor should continue to work -- just applied to a different object.
I'm assuming the HibernateTemplate is retrieved from a Spring.NET object factory...