Confusion over using generic repository in .NET Core 6 - asp.net-core

I'm developing services with a micro service architecture using .NET Core 6. I'm trying to follow clean architecture advice and have created 3 layers, Core (I put my use cases, repository interfaces, and my dto models), API layer, and infrastructure (connection with DB and implementation of repository interfaces).
The problem is the number of repositories is increasing, because I'm creating a separate repository for each different job, for example IStoreCarPricesRepository, IStoreCarSparePartRepository,..... I was thinking, would it not be wiser to have a generic repository and and just create a class to call it and do the jobless say you are getting different messages from different queues and was to store them in the respective tables?
As far as I searched for generic repository is kind of outdated, I would appreciate your comments

Yes, you can use Generic repository:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Entity;
using ContosoUniversity.Models;
using System.Linq.Expressions;
namespace DAL
{
public class GenericRepository<TEntity> where TEntity : class
{
internal SchoolContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(SchoolContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
}
Then you can instantiate and use it for each table:
private GenericRepository<Department> departmentRepository;
private GenericRepository<Employee> employeeRepository;
Read more about generic repositories here.

Repo doesn't works with jobs and messages.
The main responsibility of repository is a wrapper for common operations (CRUD) or maybe some work with tables for example count, any, some, all.
If you wish to create a microservice architecture, it is useful to check generic repositories in GitHub and create your own library and move the generic-repository here. It should be something like YourName.Microservice.Core.
After that, connect it through a nuget-extension to your Microservice.Core.
In the future, you need to extend them to avoid a duplication of code in a lot of microservices.

Related

NHibernate logging using NLog.Web.AspNetCore

I've wasted almost a whole day trying to make NHibernate log messages via NLog.Web.AspNetCore for an ASP.Net Core project – to no avail. The only example I could find is hidden deep inside the NHibernate Git repository, but it doesn't work with modern versions of the Microsoft logging libraries. Not to mention it's a really skectchy solution, given that I'd have to copy/paste the two auxiliary classes in that folder to manually bridge the loggers and logger factories between the Microsoft world and the NHibernate world.
Is there any sane, modern, elegant solution (or NuGet package) I didn't manage to identify? I feel I'm missing something simple here, but for the life of me, I don't seem able to make it work.
For clarity, I'm looking for a way to pipe NHibernate's own log messages through NLog, not to persist NLog's messages to a database using NHibernate.
Maybe you can try this (Works only from NHibernate > 5.1.0):
NHibernateLogger.SetLoggersFactory(new NHibernate.Logging.NLog.NLogLoggerFactory());
And implement NLogLoggerFactory like this:
using NHibernate;
using NLog;
using System;
using System.Collections.Generic;
namespace NHibernate.Logging.NLog
{
public class NLogLoggerFactory : INHibernateLoggerFactory
{
private readonly LogFactory _factory;
public NLogLoggerFactory(LogFactory logFactory = null)
{
_factory = logFactory ?? LogManager.LogFactory;
}
public INHibernateLogger LoggerFor(string keyName)
{
return new NLogLogger(_factory.GetLogger(keyName));
}
public INHibernateLogger LoggerFor(Type type)
{
return new NLogLogger(_factory.GetLogger(type.ToString()));
}
}
class NLogLogger : INHibernateLogger
{
private readonly ILogger _logger;
private readonly Dictionary<NHibernateLogLevel, LogLevel> LevelMapping = new Dictionary<NHibernateLogLevel, LogLevel>() {
{ NHibernateLogLevel.Trace, LogLevel.Trace },
{ NHibernateLogLevel.Debug, LogLevel.Debug },
{ NHibernateLogLevel.Info, LogLevel.Info },
{ NHibernateLogLevel.Warn, LogLevel.Warn },
{ NHibernateLogLevel.Error, LogLevel.Error },
{ NHibernateLogLevel.Fatal, LogLevel.Fatal },
{ NHibernateLogLevel.None, LogLevel.Off },
};
public NLogLogger(NLog.ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public bool IsEnabled(NHibernateLogLevel logLevel)
{
return _logger.IsEnabled(LevelMapping[logLevel]);
}
public void Log(NHibernateLogLevel logLevel, NHibernateLogValues state, Exception exception)
{
_logger.Log(LevelMapping[logLevel], exception, state.Format, state.Args);
}
}
}
Several months later (!), I finally got fed up with rolling my own micro-library for each and every project, and decided to write a public library instead: RBC.NHibernate.NLog.

Abstraction with repository pattern

I am building an application (a web api to be specific) and I want to implement the repository pattern to abstract the data access layer and prepare it for future changes.
My goal is to make the repositories interfaces abstract enough to be able to implement every technology on top of them, starting from Native SQL Client (running sql command) to orm's like EF or dapper.
I have read some articles about repositories and the interface of my generic repository looks something like that:
interface IRepository<T>
{
IEnumerable<T> FindAll();
IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);
T FindById(int id);
void Add(T entity);
void Remove(T entity);
}
I want the method FindBy to accept a linq expression because the other option is making it accept native sql and that won't work too well with technologies like linq to entity of EF.
The problem is that i also want to be able to implement a native sql repository on top of this interface and in order to implement a native sql repository, i need to run sql command, strings.
In this interface i don't accept any sql command as string, i accept linq expressions, and the native sql client can't handle linq expressions (as far as i know).
So my question is, how can i make this interface be compatible with any technology/orm/library/client/adapter, you get the idea...
Thanks,
Arik
Adbstracting repository is a good idea. I'll try to help you.
First of all, your repository must independent of persistance, so you need to remove method FindBy(Expression<Func<T, bool>> predicate), rather replace it with some kind of specification pattern:
interface IRepository<T>
{
IEnumerable<T> FindAll();
IEnumerable<T> FindBy(ISpecification<T> specification);
T FindById(int id);
void Add(T entity);
void Remove(T entity);
}
public interface ISpecification<T>
{
IEnumerable<T> Execute(DbContext context);
}
So, now we have independent repository. And then you can create implementation of specification and repository for linq-supported persistance, it can looks like this:
public class LinqRepository<T> : IRepository<T>
{
private readonly DbContext _context;
public LinqRepository(DbContext context)
{
_context = context;
}
public IEnumerable<T> FindBy(ISpecification<T> specification)
{
return specification.Execute(_context);
}
//and others...
}
public class LinqSpecification<T> : ISpecification<T>
{
private readonly Expression<Func<T, bool>> _predicate;
public LinqSpecification(Expression<Func<T, bool>> predicate)
{
this._predicate = predicate;
}
public IEnumerable<T> Execute(DbContext context)
{
return context.Set<T>().Where(_predicate).ToList();
}
}
And call like this:
IRepository<Person> repository = new LinqRepository<Person>(dbContext);
var adults = repository.FindBy(new LinqSpecification<Person>(p => p.Age > 18));
Another side, when you need to implement non-linq repository, it can look like this:
public class SqlRepository<T> : IRepository<T>
{
private readonly DbContext _context;
public SqlRepository(DbContext context)
{
_context = context;
}
public IEnumerable<T> FindBy(ISpecification<T> specification)
{
return specification.Execute(_context);
}
}
public class SqlSpecification<T> : ISpecification<T>
{
private readonly string _query;
public SqlSpecification(string query)
{
_query = query;
}
public IEnumerable<T> Execute(DbContext context)
{
return context.ExecuteSql<T>(_query);
}
}
And call:
IRepository<Person> repository = new SqlRepository<Person>(dbContext);
var adults = repository.FindBy(new SqlSpecification<Person>("SELECT * FROM Persons WHERE Age > 18"));
Of couse, it's not ideal variant, but it depends on your system architecture and other components. But it can be used as background.

Does WCF OData Service Support Projection?

I'm using WCF OData service as my application Data Provider.OData service expose a entity that I don't want to get whole entity,I create LINQ query to get projection from this Entity.
But i have error in OData Service.This is my code:
from n in NewsInfos
select new NewsInfos
{
n.NewsId,
n.NewsTitle,
n.NewsLead,
n.NewsDate
};
This is entire code:
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class NewsDataService : DataService<NewsODataModel>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.DataServiceBehavior.AcceptProjectionRequests = true;
}
}
Yes, WCF Data Services and OData support projection. Projection is codified in the URL with the $select system query option, e.g.: http://services.odata.org/Experimental/OData/OData.svc/Products?$select=Name&$format=json. The LINQ Provider in the client bits enable this similarly to what you've shown in your example. Here is one such example:
using System;
using System.Data.Services.Client;
using System.Linq;
namespace Scratch
{
public class Program
{
public static void Main()
{
var context = new DataServiceContext(new Uri("http://services.odata.org/OData/OData.svc/"));
var categories = context.CreateQuery<Category>("Categories").Select(c => new { c.Name });
Console.WriteLine("context.Categories.Where(...): {0}", categories);
foreach (var category in categories)
{
Console.WriteLine(category.Name);
}
}
}
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
}
}
One thing to consider with projection is that the magic in our client-side bits frequently requires you to use anonymous objects (hence the new { c.Name }).
Your error may be unrelated; if you're still getting the error after reading this can you update your service to return verbose errors as per http://blogs.msdn.com/b/phaniraj/archive/2008/06/18/debugging-ado-net-data-services.aspx? My guess is that you may be missing the [DataServiceKey] attribute on NewsInfos.
Just return an anonymous object from your select and it should work.
from n in NewsInfos
select new
{
n.NewsId,
n.NewsTitle,
n.NewsLead,
n.NewsDate
};

Implementing a flexible searching infrastructure using nHibernate

My aim is to implement a quite generic search mechanism. Here's the general idea:
you can search based on any property of the entity you're searching for (for example- by Employee's salary, or by Department name etc.).
Each property you can search by is represented by a class, which inherits from EntityProperty:
public abstract class EntityProperty<T>
where T:Entity
{
public enum Operator
{
In,
NotIn,
}
/// <summary>
/// Name of the property
/// </summary>
public abstract string Name { get; }
//Add a search term to the given query, using the given values
public abstract IQueryable<T> AddSearchTerm(IQueryable<T> query, IEnumerable<object> values);
public abstract IQueryable<T> AddSortingTerm(IQueryable<T> query);
protected Operator _operator = Operator.In;
protected bool _sortAscending = false;
public EntityProperty(Operator op)
{
_operator = op;
}
//use this c'tor if you're using the property for sorting only
public EntityProperty(bool sortAscending)
{
_sortAscending = sortAscending;
}
}
all of the properties you're searching / sorting by are stored in a simple collection class:
public class SearchParametersCollection<T>
where T: Entity
{
public IDictionary<EntityProperty<T>,IEnumerable<object>> SearchProperties { get; private set; }
public IList<EntityProperty<T>> SortProperties { get; private set; }
public SearchParametersCollection()
{
SearchProperties = new Dictionary<EntityProperty<T>, IEnumerable<object>>();
SortProperties = new List<EntityProperty<T>>();
}
public void AddSearchProperty(EntityProperty<T> property, IEnumerable<object> values)
{
SearchProperties.Add(property, values);
}
public void AddSortProperty(EntityProperty<T> property)
{
if (SortProperties.Contains(property))
{
throw new ArgumentException(string.Format("property {0} already exists in sorting order", property.Name));
}
SortProperties.Add(property);
}
}
now, all the repository class has to do is:
protected IEnumerable<T> Search<T>(SearchParametersCollection<T> parameters)
where T : Entity
{
IQueryable<T> query = this.Session.Linq<T>();
foreach (var searchParam in parameters.SearchProperties)
{
query = searchParam.Key.AddSearchTerm(query, searchParam.Value);
}
//add order
foreach (var sortParam in parameters.SortProperties)
{
query = sortParam.AddSortingTerm(query);
}
return query.AsEnumerable();
}
for example, here's a class which implements searching a user by their full name:
public class UserFullName : EntityProperty<User>
{
public override string Name
{
get { return "Full Name"; }
}
public override IQueryable<User> AddSearchTerm(IQueryable<User> query, IEnumerable<object> values)
{
switch (_operator)
{
case Operator.In:
//btw- this doesn't work with nHibernate... :(
return query.Where(u => (values.Cast<string>().Count(v => u.FullName.Contains(v)) > 0));
case Operator.NotIn:
return query.Where(u => (values.Cast<string>().Count(v => u.FullName.Contains(v)) == 0));
default:
throw new InvalidOperationException("Unrecognized operator " + _operator.ToString());
}
}
public override IQueryable<User> AddSortingTerm(IQueryable<User> query)
{
return (_sortAscending) ? query.OrderBy(u => u.FullName) : query.OrderByDescending(u => u.FullName);
}
public UserFullName(bool sortAscending)
: base(sortAscending)
{
}
public UserFullName(Operator op)
: base(op)
{
}
}
my questions are:
1. firstly- am I even on the right track? I don't know of any well-known method for achieving what I want, but I may be wrong...
2. it seems to me that the Properties classes should be in the domain layer and not in the DAL, since I'd like the controller layers to be able to use them. However, that prevents me from using any nHibernate-specific implementation of the search (i.e any other interface but Linq). Can anybody think of a solution that would enable me to utilize the full power of nH while keeping these classes visible to upper layers? I've thought about moving them to the 'Common' project, but 'Common' has no knowledge of the Model entities, and I'd like to keep it that way.
3. as you can see by my comment for the AddSearchTerm method- I haven't really been able to implement 'in' operator using nH (I'm using nH 2.1.2 with Linq provider). any sugggestions in that respect would be appriciated. (see also my question from yesterday).
thanks!
If you need good API to query NHIbernate objects then you should use ICriteria (for NH 2.x) or QueryOver (for NH 3.x).
You over complicating DAL with these searches. Ayende has a nice post about why you should not do it
I ended up using query objects, which greatly simplified things.

NHibernate and Structure Map

So I really like working with NHibernate but always used Spring.Net with it.
I recently came across StructureMap by Jeremy Miller and really like it better than Spring.Net. On his StructureMap site he promises an example on how to use NHibernate and StructureMap together. Unfortunately he has not had time to do it (or I can't find it).
So does anyone have an example on how to handle the NHibernate Session with StructureMap?
So, I apologize that we did not get the NHibernate with StructureMap example done earlier. Eventually, I would like to publish it in the StructureMap documentation, but I need some feedback first. You can see the full example on my blog:
http://trason.net/journal/2009/10/7/bootstrapping-nhibernate-with-structuremap.html
That being said, I can hit the highlights here. There is an NHibernateRegistry that makes available four things: an NHibernate.Configuration (as a Singleton), an ISessionFactory (as a Singleton), an ISession (scoped Hybrid (HttpContext if available, falling back to Thread local storage)), and a very simple IUnitOfWork. Also, there is an HttpModule to manage the UnitOfWork per web request.
Here is the code for the NHibernateRegistry:
using NHibernate;
using NHibernate.ByteCode.Castle;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernateBootstrap.Core.Domain;
using StructureMap.Attributes;
using StructureMap.Configuration.DSL;
using Environment=NHibernate.Cfg.Environment;
namespace NHibernateBootstrap.Core.Persistence
{
public class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
var cfg = new Configuration()
.SetProperty(Environment.ReleaseConnections, "on_close")
.SetProperty(Environment.Dialect, typeof(SQLiteDialect).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionDriver, typeof(SQLite20Driver).AssemblyQualifiedName)
.SetProperty(Environment.ConnectionString, "data source=bootstrap.sqlite;Version=3")
.SetProperty(Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName)
.AddAssembly(typeof(Blog).Assembly);
var sessionFactory = cfg.BuildSessionFactory();
ForRequestedType<Configuration>().AsSingletons().TheDefault.IsThis(cfg);
ForRequestedType<ISessionFactory>().AsSingletons()
.TheDefault.IsThis(sessionFactory);
ForRequestedType<ISession>().CacheBy(InstanceScope.Hybrid)
.TheDefault.Is.ConstructedBy(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());
ForRequestedType<IUnitOfWork>().CacheBy(InstanceScope.Hybrid)
.TheDefaultIsConcreteType<UnitOfWork>();
ForRequestedType<IDatabaseBuilder>().TheDefaultIsConcreteType<DatabaseBuilder>();
}
}
}
Here is the code for the Unit of Work:
using System;
using NHibernate;
namespace NHibernateBootstrap.Core.Persistence
{
public interface IUnitOfWork : IDisposable
{
ISession CurrentSession { get; }
void Commit();
}
}
using NHibernate;
namespace NHibernateBootstrap.Core.Persistence
{
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
CurrentSession = _sessionFactory.OpenSession();
_transaction = CurrentSession.BeginTransaction();
}
public ISession CurrentSession { get; private set;}
public void Dispose()
{
CurrentSession.Close();
CurrentSession = null;
}
public void Commit()
{
_transaction.Commit();
}
}
}
Here is the NHibernateModule for web applications:
using System;
using System.Web;
using NHibernateBootstrap.Core.Persistence;
using StructureMap;
namespace NHibernateBootstrap.Web
{
public class NHibernateModule : IHttpModule
{
private IUnitOfWork _unitOfWork;
public void Init(HttpApplication context)
{
context.BeginRequest += ContextBeginRequest;
context.EndRequest += ContextEndRequest;
}
private void ContextBeginRequest(object sender, EventArgs e)
{
_unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
}
private void ContextEndRequest(object sender, EventArgs e)
{
Dispose();
}
public void Dispose()
{
_unitOfWork.Dispose();
}
}
}
Does this help: http://devlicio.us/blogs/billy_mccafferty/archive/2007/02/05/inject-di-container-into-domain-objects-with-nhibernate.aspx
Edit here: I posted this comment before wbinford's answer was posted. I still think using NCommon is good, but his answer above is a little cleaner and does not require the use of another third party tool.
I really didn't get the answers I was looking for but I found a nice framework called NCommon. It implements the unit of work pattern along with the repository pattern with NHibernate, LinqToSql or the Entity Framework. It also handled the NHibernate ISession as well as configuration for NHibernate. I used the tool with StructureMap and NHibernate. I did have to get the service adapter for StructureMap, but once set up it works rather nicely.