6
I’m thinking of a way to apply the pattern (multi-tenant), raised in that question (Standard that has contributed to the reliability of software that needs to meet complex models such as multi-business models), in an application c# with Entityframework.
As the title of the issue presents, the pattern is based on a way to protect the application so that data from a Reseller, its clients companies and its customers do not have their data presented to others.
I believe the pattern multi-tenant ("multi-tenant") would be suitable for this case - although it is a single operator of a single company to access the various tenants. That article briefly describes the philosophy behind the multitenancy.
It is a multi-profile access application.
So I thought I’d do this in a base class for the repositories.
So I started to create something like this:
An interface to set a pattern:
public interface IRepository<TContext, T, TKey> : IDisposable
where TContext : DbContext, new()
where T : class
{
T Get(TKey id);
IQueryable<T> GetAll(Expression<Func<T, bool>> filter);
IQueryable<T> Query(params Expression<Func<T, object>>[] includes);
T Add(T entity);
List<T> AddRange(List<T> items);
bool Edit(T entity);
bool Delete(TKey id);
bool Delete(T entity);
int Delete(Expression<Func<T, bool>> where);
int SaveChanges();
}
And an abstract class, which implements this interface, to be inherited by the repository classes:
public abstract class CustomRepository<TContext, T, TKey> : IRepository<TContext, T, TKey>
where TContext : DbContext, new()
where T : class
{
private TContext _context = null;
private bool _responsibleContext = false;
/// <summary>
/// constructor
/// </summary>
public CustomRepository()
{
_context = new TContext();
_responsibleContext = true;
}
/// <summary>
/// constructor with a DbContext param
/// </summary>
/// <param name="context">A DbContext param</param>
public CustomRepository(TContext context)
{
_context = context;
_responsibleContext = false;
}
/// <summary>
/// disposer
/// </summary>
public void Dispose()
{
if (_responsibleContext && _context != null)
_context.Dispose();
GC.SuppressFinalize(this);
}
#region other interface implementations ...
public T Get(TKey id)
{
return _context.Set<T>().Find(id);
}
public IQueryable<T> GetAll(Expression<Func<T, bool>> filter)
{
return Query().Where(filter);
}
public IQueryable<T> Query(params Expression<Func<T, object>>[] includes)
{
IQueryable<T> set = _context.Set<T>();
foreach (var include in includes)
set = set.Include(include);
return set;
}
public T Add(T entity)
{
_context.Set<T>().Add(entity);
SaveChanges();
return entity;
}
public List<T> AddRange(List<T> items)
{
_context.Set<T>().AddRange(items);
SaveChanges();
return items;
}
public bool Edit(T entity)
{
var result = false;
_context.Entry<T>(entity).State = EntityState.Modified;
if (SaveChanges() > 0)
result = true;
return result;
}
public bool Delete(TKey id)
{
var entity = Get(id);
return Delete(entity);
}
public bool Delete(T entity)
{
_context.Entry(entity).State = EntityState.Deleted;
return SaveChanges() > 0;
}
public int Delete(Expression<Func<T, bool>> where)
{
var entries = Query().Where(where);
_context.Set<T>().RemoveRange(entries);
return SaveChanges();
}
public int SaveChanges()
{
return _context.SaveChanges();
}
#endregion other interface implementations ...
}
And if I understood the standard proposal correctly, I would have to pass an instance reference from my Session User, so I could change the methods to something like:
public T Get(TKey id)
{
var entry = _context.Set<T>().Find(id);
if (entry.RevendaId == userSession.RevendaId &&
entry.EmpresaId == userSession.EmpresaId &&
entry.ClienteId == userSession.ClienteId)
return entry;
else
return null;
}
And also:
public IQueryable<T> Query(params Expression<Func<T, object>>[] includes)
{
IQueryable<T> set = _context.Set<T>();
foreach (var include in includes)
set = set.Include(include);
set = set.Where(x => x.RevendaId == userSession.RevendaId &&
x.EmpresaId == userSession.EmpresaId &&
x.ClienteId == userSession.ClienteId);
return set;
}
And apply this approach to all methods.
Well, I have two questions:
This approach in trying to implement the standard would be a correct way?
1.1. If not, how would a correct implementation of this standard in the presented scenario?
If yes, how do I pass an instance of the Session User to the repository instance?
to make your situation worse, there is still the authorization, that each user will have certain authorizations per company kkk is quite complex this, I will follow the answers
– Rod
You like this repository junk, right? Jeez, life.
– Leonel Sanches da Silva
@Tiagosilva I will answer your question, but first I will recommend you this reading here from the creator of the Entity Framework. Then I think it will become clearer why the EF repository is a gadget.
– Leonel Sanches da Silva
@Ciganomorrisonmendez: I think you made a little mess... the Entity Framework is from Microsoft. Ayende is the guy from Nhibernate.
– Miguel Angelo
@Miguelangelo I don’t. This guy right here, then.
– Leonel Sanches da Silva
Ah tá... the site refers to an Entity Framework Profiler, made by Ayende.
– Miguel Angelo
That Ayende is the Dick of The Galaxies.
– Leonel Sanches da Silva