asp.net Generic repository find by property - c#

I am using Generic Repositories with ASP.NET. Now I am trying to find an object by the user Id which requires to access a property of the class, but ofcourse in the linq expression the property is not know, because it does not know the type yet. Is there any way around this?
public virtual IEnumerable<T> GetByUser(string userId)
{
if (typeof(T).GetProperty("Employee") != null)
{
return Db.Set<T>().Where(x => x.Employee.Id == userId);
}
return new List<T>();
}
the "x.Employee.Id" gets the error that there is no definition of Employee. That is to be expected. Do I need to do this in an entire different way or does somebody knows how to fix this?
I hope anybody can help!

Use interfaces so that you know T will have certain properties. Or use a base type and then use constraints on the generic parameter.
public virtual IEnumerable<T> GetByUser(string userId) where T : IEmployee
{
return Db.Set<T>().Where(x => x.Employee.Id == userId);
}
And where IEmployee looks like this
public interface IEmployee
{
Employee Employee { get; set; }
}
Obviously this is a bit crude, but depending on your entities this could be an approach. You could always map out everything and then build up your interfaces for the shared properties etc.
However to be honest I think your best approach is to have a more functional set of generic repositories. For example a base repo, and then an EmployeeRepostiory that knows that T will be an Employee.
MSDN Article on Constraints

Related

Generic extension for EF entities

Task: write a generic extension for Entity Framework entities
I am not sure if this is even possible due to the fact that each entity usually will have differing properties, but I have a group of entities that share a few common properties and all I was wondering if it is even possible to build a generic extension instead of always having to write out the same code for each entity.
I spent a bit of time researching this, but there is not much , which leads me to believe this just is not possible.
Anyway, contrary to my better judgment I am going to ask a stupid question on StackOverFlow.
This is what I was thinking, but obviously a non compile-able example, but at least you will get the idea.
public static List<TEntity> Generic<TEntity>(this DbContext db, string name)
{
return db.TEntity.Where(s => s.Name == name);
}
I poke in the right direction would be appreciated.
And just for clarity, I have never spent a single hour in a classroom for programming, I am self taught, so if it is not possible to this, could the answer explain please explain technically why this is not possible in Entity Framework. As I could not find anything substantial myself.
Thanks to #Bagus Tesa, I was able to solve this.
As Bagus tesa states, make an interface that references the common properties of the Entities and refference the interface with the Entities and make an extension that way.
The code I used,
public static IQueryable<IFilterEntity> FilterEntity(this BaseViewModel vm,
IQueryable<IFilterEntity> list)
{
return list.Where(s => s.Name == vm.name &&
s.DateMonth == vm.Month &&
s.DateYear == vm.Year);
}
The interface,
public interface IFilterEntity
{
string Name { get; set; }
int? DateYear { get; set; }
int? DateMonth { get; set; }
}
The BaseViewModel,
public class BaseViewModel
{
string Name => RootVm.Name;
int? DateYear => RootVm.SelectedDate.Month;
int? DateMonth => RootVm.SelectedDate.Month;
}
Thanks for all the help with. And I hope this helps someone else.
Use this
public IEnumerable<TEntity> Filter(Expression<Func<TEntity, bool>> filter, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
{
db.Set<TEntity>().AsNoTracking().AsQueryable().Where(filter);}

Switches for LazyLoading with Repository pattern

By default LazyLoading is disabled in my DbContext. I use repository pattern and in some case I need to get only simple object and in other I need to get object with values of navigations properties.
How can I implement something like switches for LazyLoading?
Any help will be appreciated
I have one solution that works but I'm not sure that it is correct:
in interface of repository I added new property
public interface IRepository<T> where T : BaseEntity
{
T GetById(object id);
void Insert(T entity);
.....
bool LazyLoadingSwitches { set; }
}
Then implemented it:
public bool LazyLoadingSwitches
{
set
{
this.context.Configuration.LazyLoadingEnabled = value;
}
}
and when I need to get model with related data then I use in controller:
repository.LazyLoadingSwitches = true;
name = order.Customer.FullName;
repository.LazyLoadingSwitches = false;
Please suggest me what is the best solution for that?
Just my two cents:
I think implementing a wrapper around the this.context.Configuration.LazyLoadingEnabled = value; call is OK. I would implement it as a method though, a write only property is quite odd.
In my coding I let the code that executes the query decide if it wants to use lazy loading or .Include statements. Most important is that the code that is going to consume the class that was returned finds all data in it that is needs.
I think you can use include:
order.Include("Customer");
var name = order.Customer.FullName;
Sample with lambda expression:
order.Include(o => o.Customer);
var name = order.Customer.FullName;

Domain model vs Entity FW: Is this a case when splitting in a persistence model is usefull?

In a DDD approach, I have a Domain Model (DM), with a rich behaviour. Suppose I have a root entity, called Order and relative LineOrder. The exposed collection of LineOrder need to be a IReadOnlyCollection since none can alter the collection arbitrarily. In code:
public class Order : AggregateRoot {
// fields
private List<LineOrder> lineOrder;
// ctors
private Order() {
this.lineOrder = new List<LineOrder>();
// other initializations
}
// properties
public IReadOnlyCollection<LineOrder> LineOrder {
get
{
return lineOrder.AsReadOnly();
}
}
// behaviours
}
So far, so good. But when I want to persist this domain I have some technology restrictions imposed by Entity Framework (a key is needed even if I have a value object, a parameterless constructor and so on) that is not a perfect match with a DDD approach.
Another limitation that I have is:
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
ToTable("Order");
HasMany<LineOrder>(m => m.LineOrder); // Exception: Cannot convert from IReadOnlyCollection to ICollection
}
}
I cannot cast IReadOnlyCollection to ICollection (incidentally, if LineOrder was an ICollection everything was OK!).
For the reasons I have expressed above: could be usefull in this case create a Persistence Model (with belonging cons: mapping DM/PM and viceversa)?
Are there an alternative? And, above all: are there an alternative that well fit a DDD approach?
Have you tried declaring the LineOrder collection as protected? This way EF has access but consumers do not.
// properties
protected ICollection<LineOrder> LineOrder { get; set; }
You can then expose this collection in a read-only manner to the end user with:
public IReadOnlyCollection<LineOrder> ReadOnlyLineOrder
{
get
{
return LineOrder.ToList().AsReadOnly();
}
}

Dealing with a Generic Type cast

I have a generic type (RoleEntity) that may or may not implement an interface that is also generic (IActor). Background on the design
is below, but the short story is that a RoleEntity is a role that maybe assumed by an Actor and that RoleEntity may optionally
be an IActor with it's own Roles.
So if I want to access the Roles of a an Actor's role, I can think of two options
Cast the role safely to an Actor{T}. This is what I would do if I wasn't casting one generic to another; it seems the only way to do this is with some non-trivial reflection.
Use dynamic.
The code below is a bastardized mix of both. I am using reflection but not far enough to actually figure out the exact IActor{T}. Then because I have an indeterminate type I use IEnumerable{dynamic}. It doesn't feel like good code but I don't know how to do better.
Can someone present some cleaner code?
static void GetRoleHeirarchyString<T>(IActor<T> actor)
where T : Entity, IActor<T>
{
foreach (var role in actor.AllRoles) {
// do something with the Role;
// trivial reflection
var type = role.GetType();
var pi = type.GetProperty("AllRoles");
if (pi == null)
continue;
var roles = pi.GetValue(role, null) as IEnumerable<dynamic>; // dynamic
foreach (var r in roles) {
// do something with the Role;
}
}
}
Backround
Below are two interfaces that are part of a solution implementing Roles.
In this design, a class that might be expressed as one or more Roles is called an Actor. The class that is expressing a Role (called a 'Role'!)
uses an instance of the Actor to forward properties of interest from the Actor. So for example, if a Person class is an Actor for several roles
in an application )ie, Student, Mother, and Employee) then each Role might use an instance of the Person to have a common Name property that
is based on the Person.
Roles may or may not also be Actors; an Employee may be a ProjectManager or even a Buyer of something her employers sells. But a Student
may just be a role for a Person and not an Actor.
public class RoleEntity<T> : Entity where T : Entity, IActor<T>
{
public T Actor { get; protected set; }
...
}
public interface IActor<T> where T : Entity, IActor<T>
{
bool AddRole(IRoleFor<T> role);
bool RemoveRole(IRoleFor<T> role);
bool HasRole(IRoleFor<T> role);
IEnumerable<IRoleFor<T>> AllRoles { get; }
}
Sometimes it is possible to define non-generic interface IRoleEntity and have your RoleEntity<T>implement IRoleEntity.
If you declare a method IRole.DoSomethingWithTheRole, then you can implement it in RoleEntity<T>.
And you can call it without knowing exact RoleEntity<T> type thanks to polymorphism.
Same trick you may want to do with IActor<T> inheriting IActor.
It doesn't always make sense, but I don't have enough understanding of your problem.

Can I create "relay" or "genericized" properties for Entity Framework models?

I hope my wording makes sense... I wasn't quite sure exactly how to explain what I'm looking to do.
I have a method in a generic class that returns a list of entities as follows:
public abstract class ChildCRUDController<TModel> : CRUDController<TModel, ... >
where TModel : IChildEntity
public ViewResult List(int id)
{
return View(repository.GetMany(x => x.ParentID == id));
}
This controller is implemented by quite a few other controllers. The issue I have is that not all entities that implement IChildEntity have the same parent type. To get around this issue I created ParentID properties for all the models that implement IChildEntity so they could use the same controller.
public partial class PhoneNumber : IChildEntity
{
public int ParentID
{
get { return CustomerID; }
set { CustomerID = ParentID; }
}
}
and...
public partial class Transaction : IChildEntity
{
public int ParentID
{
get { return LeaseID; }
set { LeaseID= ParentID; }
}
}
But when I call the List method above I get the following error:
The specified type member 'ParentID' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Is there any way I can achieve the result I am looking for without pulling the object set into memory or renaming all the properties on the entities themselves?
Thanks!
If you are willing to pass the field name into the List method and to construct your own query you can do it using the techniques described in this StackOverflow article:
Querying Entity with LINQ using Dyanmic Field Name
Or you could supply the ChildCRUDController with another generic type parameter constrained to an interface that supplies the field name and again use it dynamically.

Categories