问题
I am creating an Intranet website with ASP.NET MVC and Onion Architecture. I have been implementing the repository pattern but I have a difficulty.
Let's say I have a Document table with IDDocument in it. Then this is my repo(with just one method):
class Repository<T> : IRepository<T> where T : class
{
private readonly PrincipalServerContext context;
private DbSet<T> entities;
//Constructor and stuff here
public T Get(long id)
{
return entities.SingleOrDefault(s => s.IDDocument == id);//Here is my problem
}
}
The problem is that I cannot use this since T is not recognized as being from Document table. Solution is to create a BaseEntity:
public class BaseEntity{
public int ID{get;set;}
}
Then My Document POCO becomes:
public class Document : BaseEntity{
//Properties here
}
And my Repo:
class Repository<T> : IRepository<T> where T : BaseEntity
{
private readonly PrincipalServerContext context;
private DbSet<T> entities;
public T Get(long id)
{
return entities.SingleOrDefault(s => s.ID == id);//Here is my problem
}
}
But I don't want to do this ideally. What I like in the generic repo is that it allows me to not repeat the same code for all the different tables (I have 300+). But having a BaseEntity would also mean restructuring alot of what I have already done. Is it possible to have a Generic repo that you can apply on any POCO without this BaseEntity class?
Thanks for your help
回答1:
You're calling the Queryable.SingleOrDefault method.
Its second parameter has the type Expression<Func<T, bool>>
so you can build expression manually, using as identifier property as you wish.
Short example:
public T Get(long id)
{
var idName = "ID" + typeof(T).Name; // For Document would be IDDocument
var parameter = Expression.Parameter(id.GetType());
var property = Expression.Property(parameter, idName)
var idValue = Expression.Constant(id, id.GetType());
var equal = Expression.Equal(property, idValue);
var predicate = Expression.Lambda<Func<T, bool>>(equal, parameter);
return entities.SingleOrDefault(predicate);
}
Imagine you wrote lambda function (T obj) => obj.IdProperty == id
.
Here obj
is parameter
, and idName
should store "IdProperty"
string.
property
means obj.IdProperty
, idValue
means the value if id
.
equal
means obj.IdProperty == id
, and predicate means whole expression (T obj) => obj.IdProperty == id
.
来源:https://stackoverflow.com/questions/44591796/does-a-generic-repository-need-a-base-entity-class-to-be-applied-everywhere