7
I need to create a wrapper for ObjectSet
to create a centralized access control.
The goal is to implement CA without making changes to existing queries in the system, which in this case are spread throughout the code (there is no centralized layer for data access).
The connection to the bank uses a ObjectContext
.
The wrapper of ObjectSet
created, is this:
public class ObjectSetWrapper<TEntity> : IQueryable<TEntity> where TEntity : EntityObject
{
private IQueryable<TEntity> QueryableModel;
private ObjectSet<TEntity> ObjectSet;
public ObjectSetWrapper(ObjectSet<TEntity> objectSetModels)
{
this.QueryableModel = objectSetModels;
this.ObjectSet = objectSetModels;
}
public ObjectQuery<TEntity> Include(string path)
{
return this.ObjectSet.Include(path);
}
public void DeleteObject(TEntity @object)
{
this.ObjectSet.DeleteObject(@object);
}
public void AddObject(TEntity @object)
{
this.ObjectSet.AddObject(@object);
}
public IEnumerator<TEntity> GetEnumerator()
{
return QueryableModel.GetEnumerator();
}
public Type ElementType
{
get { return typeof(TEntity); }
}
public System.Linq.Expressions.Expression Expression
{
get { return this.QueryableModel.Expression; }
}
public IQueryProvider Provider
{
get { return this.QueryableModel.Provider; }
}
public void Attach(TEntity entity)
{
this.ObjectSet.Attach(entity);
}
public void Detach(TEntity entity)
{
this.ObjectSet.Detach(entity);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.QueryableModel.GetEnumerator();
}
}
He’s not the type ObjectSet
, but this is not important, it only needs to be used in queries LinqToEntities
. And it even works for simple queries, like this one:
//db.Produto é do tipo ObjectSetWrapper<Produto >
var query = (from item in db.Produto where item.Quantidade > 0 select new { item.Id, item.Nome, item.Valor });
var itensList = query.Take(10).ToList();
But when there is a * subquery*, like this:
//db.Produto é do tipo ObjectSetWrapper<Produto>
var query = (from item in db.Produto
select new
{
Id = item.Id,
Nome = item.Nome,
QuantidadeVendas = (from venda in db.Venda where venda.IdProduto == item.Id select venda.Id).Count()
}).OrderByDescending(x => x.QuantidadeVendas);
var productsList = query.Take(10).ToList();
I get a NotSupportedException
, stating that it is not possible to create a constant of the type of my subquery (in the case, Venda
):
Unable to create a Constant value of type 'Mynamespace.Model.Venda'. Only Primitive types or enumeration types are supported in this context.
How I make this query work? I don’t need you to wrapper be the type ObjectSet
, only that it can be used in queries, keeping the queries of the system working.
Updated
Update the Objectsetwrapper class to implement IObjectSet<TEntity>
as indicated by Miguel Angelo, but the errors continue. Now the class presents this signature:
public class ObjectSetWrapper<TEntity> : IObjectSet<TEntity>, IQueryable<TEntity> where TEntity : EntityObject
To reinforce, the idea of wrapper is to be able to perform access control checks on queries of query, therefore it is important to keep queries with existing entities in the system working.
Extension Methods were designed exactly for this type of problem, where it is not possible or desirable to change the base classes. I believe this would be a better solution to your problem rather than creating a wrapper class.
– Wagner DosAnjos
Apparently you have a Iqueryable in return sales, you wouldn’t even need to materialize the query in objects before. A kick, try to remove the
.OrderByDescending(x => x.QuantidadeVendas)
and use only after materializing the list, who knows your problem is only there.– iuristona
I just tried it here, it didn’t work either, it’s still the same mistake.
– IPValverde
You managed to solve the problem?
– Miguel Angelo
Yes, they answered me in the "original" OS, but later I put the answer here.
– IPValverde