Confuse with Generics and Entity Framework - c#

I am new to c# and now bit confused with Generics and Entity Framework. I have two tables in database, which I retrieve in my code using Entity Framework. On my aspx page, I have a grid which should populate the data based on what table user selects.
In future there will be more tables. So I wanted to write a factory pattern to get the source list for datagrid. I can not make it to work because i am very confused.
Here is my code for BaseClass and two child classes.
static class Factory
{
public static ReportBase GetReport(string name)
{
switch (name)
{
case "Child1":
return new Child1();
case "Child2":
return new Child1();
default:
return null;
}
}
}
//Base Class
class ReportBase<T>
{
public List<T> _list;
public abstract void Load();
public abstract List<T> Filter(DateTime statrtDate, DateTime endDate);
}
//Child 1
class Child1 : ReportBase
{
public List<GetChild1> _list;
public Child1(){}
public override void Load()
{
//GetChild1 is the name of database table
var info = from p in Context.GetChild1 select p;
_list = info.ToList();
}
public List<GetChild1> Filter(DateTime startDate, DateTime endDate)
{
var filteredValues = from p in _list where p.UploadedDate <= startDate select p;
return filteredValues.ToList();
}
}
//Child 2
class Child2 : ReportBase
{
public List<GetChild2> _list;
public Child2() { }
public override void Load()
{
//GetChild2 is the name of database table
return (from p in Context.GetChild2 select p).ToList();
}
public List<GetChild2> Filter(DateTime startDate, DateTime endDate)
{
return (from p in _list where p.UploadedDate <= startDate select p).ToList();
}
}
Can Someone please correct the code accordingly? Do I have to use Generics here? I tried using it in BaseClass but it doesn't work properly, because I have to fix my child classes accordingly, for which I have no clue.

First of all, with generics you can write better code that is more readable and short.
I think it is better not to use a factory class for repositories in the end you need to know which type you are dealing with it in your code such as:
Child1 report = new Child1();
report.SomeBehaviorInChild1(); // this is not achievable with base class.
If you want to use this factory you can do the following:
ReportBase report = Factory.GetReport();
Secondly, it is a bad idea to let your list public because you don't want to those who are using your class to create a new list from their code such as:
report._list = new List();
You don't want this thing to happen to the objects in your class. So it is better to have your list private and depend only on the methods to return the data source of your report.
private List _list;
public List<T> GetDataSource()
{
return _list;
}
Thirdly, if you implement a generic reportbase you won't need to write the child classes unless they have something special that the base doesn't implement.
Fourthly, the current implementation of Filter method is soooo bad because what you are doing here is getting all the records from database then filtering them in memory. This implementation is a bad practice. A better approach is to use the IQueryable which is a deffered execution object i.e. the result won't be populated until you request it.
public List<GetChild1> FilterExample()
{
IQueryable<GetChild1> result = _context.GetChild1;
result = from p in result
where p.UploadDate < startDate;
select p;
//until this moment the query is still not send to the database.
result = result.OrderBy(p => p.UploadDate);
//when you call the ToList method the query will be executed on the database and the list of filtered and sorted items will be returned. Notice the sorting and filtering is done in the database which is faster than doing it in memory
List<GetChild1> populatedResult = result.ToList();
return populatedResult;
}
So this was a better approach to your problem. I think it is good for you to read a book called "More Effective C# 2008" it talks about queryable and linq in general.
Now if we apply this on your BaseReportClass we can get the following:
//Base Class
class ReportBase<T> where T: class
{
private DbContext _context;
public ReportBase(DbContext context)
{
_context = context;
}
//I think GetAll is a more suitable name for your method than load :D
public IQueryable<T> GetAll()
{
return _context.Set<T>();
}
public IQueryable<T> Filter(Func<T,bool> filterFunction)
{
var result = from p in GetAll()
where filterFunction(p)
select p;
return result;
}
}
Now to defining the additional behavior for the child classes.
//Child 1
class Child1 : ReportBase<GetChild1>
{
public ReportBase(DbContext context):base(context)
{
}
public List<GetChild1> FilterOnStartDate(DateTime startDate)
{
//I don't know if you are familiar with lambda expressions but if you are not you can research it on the internet.
//The parameter here is converted into a method that its parameter is "p" of type GetChild1
// and the body is "p.UploadDate < startDate".
// Note you can remove the type of the parameter because the compiler can predict it.
return Filter((GetChild1 p) => p.UploadDate < startDate).ToList();
}
}
This is the code that uses your classes:
Child1 report = new Child1(new GetChild1Entities());
report.FilterOnStartDate(DateTime.Now);
Hope this was useful.

Generics for defining how to display each entity type (or table) is the wrong approach.
Instead, using a pattern such as MVVM or MVC, where according to the type of the data (the model) you select a view.
MVVM
MVC
MVC for ASP.NET

Related

What is the best way to create a reusable function to return a value based on related data in an EF Core data model?

I have a standard EF Core data model with several one-many and many-to-many relationships.
I want to create a way to produce various data calculations or commonly run procedures. These should return values to be used throughout the application and not values to be stored in the database.
I'll give a fictional example here of a scenario:
Entity 1 - YearGroup
Entity 2 - Student
Relationship - One YearGroup to many Students
Now I understand you could simply write in the controller:
int student = _context.Students.Where(s => s.YearGroupId == ygId).Count()
But let's say I wanted to simplify this by creating a method somewhere which returns data such as this, so I don't have to specify the query every time I get the number of Students in a YearGroup. I appreciate this is a simple example, but others could be more complex.
I was thinking adding a field to yeargroup.cs model such as:
public int TotalStudents { //code here to get students from students table }
Which I could then use like:
#model.YearGroup.TotalStudents
But I don't know how to get this to include relational data, i.e. from the students table.
I would prefer not create random methods in separate, unrelated classes such as GetStudentsInYearGroup(ygId). It would be nice to include this in the object model if possible.
What would be the best practice way of acheiving this?
Note: I don't have a code editor nor a project setup so what I am going to write might not be compilable.
As simple as your fictional example
For any case as simple as your fictional example, if you just want to get the total students per a year group, and I assume their relationships are properly setup, you can just simply use the navigation property:
// Find the target year group
var yearGroup = _context.YearGroups
.SingleOrDefault(x => x.Id == ygId);
int totalStudents = 0;
if (yearGroup != null)
{
totalStudents = yearGroup.Students.Count();
}
Extension methods
The other way I can think of is to define whatever you need as extension methods of the entity:
public static class YearGroupExtensions
{
public static int GetTotalStudents(this YearGroup yearGroup)
{
if (yearGroup == null)
{
return 0;
}
return yearGroup.Students.Count();
}
public static int GetTotalStudents(this YearGroup yearGroup, Gender gender)
{
if (yearGroup == null)
{
return 0;
}
if (gender == null)
{
return yearGroup.GetTotalStudents();
}
return yearGroup
.Students
.Count(x => x.Gender == gender);
}
}
// usage
// YearGroup yearGroup = GetYearGroup(ygId);
// int totalStudents = yearGroup.GetTotalStudents();
Repository Pattern
If you find yourself repeating similar methods you need for most of your entities, it might be good to define a generic repository for them.
I am not here arguing whether this is just a wrapper of DbContext as that itself is already using repository pattern.
public interface IEntity { }
public interface IRepository<T> where T : IEntity
{
IEnumerable<T> GetAll();
T GetById(int id);
void Insert(T entity);
...
}
public abstract class RepositoryBase<T> : IRepository<T> where T : IEntity
{
protected readonly AppDbContext _dbContext;
protected DbSet<T> _entities;
private RepositoryBase(AppDbContext dbContext)
{
_dbContext = dbContext;
_entities = dbContext.Set<T>();
}
public virtual IEnumerable<T> GetAll()
{
return _entities.AsEnumerable();
}
...
}
public class YearGroupRepository : RepositoryBase<YearGroup>
{
...
}
Separate Persistence and Domain Model
This is my preference just because I'm a DDD guy, and I want to build anything from the domain first (what businesss problems you're trying to solve), without thinking its backend persistence.
The basic idea here is to have 2 sets of models. They could be similar, or totally different. 1 set of models is called the domain model, which reflects your business domain. The other set of models is called the persistence model. That could be your regular Entity Framework Entities.
More on this: https://stackoverflow.com/a/14042539/2410655
Given a DbContext, an entity and a navigation property, you can construct an IQueryable as follows;
public static IQueryable AsQueryable(DbContext context, object entity, string navigation){
var entry = context.Entry(entity);
if (entry.State == EntityState.Detatched)
return null;
var nav = entry.Navigation(navigation);
return nav.Query();
}
I feel like there should be an existing method for this, but I can't seem to find one right now.
You should then be able to use this method in a fairly generic way for any navigation property, without needing to replicate the foreign key criteria all over the place.
public int TotalStudents(DbContext context) =>
AsQueryable(context, this, nameof(Students))?.Count() ?? 0;
While this would add some minor performance overhead, you could extract the base entity and navigation property from a LamdaExpression, and write some extension methods;
public class QueryableVisitor : ExpressionVisitor
{
private object obj;
public object BaseObject { get; private set; }
public string Navigation { get; private set; }
protected override Expression VisitConstant(ConstantExpression node)
{
BaseObject = obj = node.Value;
return base.VisitConstant(node);
}
protected override Expression VisitMember(MemberExpression node)
{
Visit(node.Expression);
BaseObject = obj;
if (node.Member is PropertyInfo prop)
obj = prop.GetValue(obj);
else if (node.Member is FieldInfo field)
obj = field.GetValue(obj);
Navigation = node.Member.Name;
return node;
}
}
public static IQueryable<T> AsQueryable<T>(this DbContext context, Expression<Func<IEnumerable<T>>> expression)
{
var visitor = new QueryableVisitor();
visitor.Visit(expression);
var query = AsQueryable(context, visitor.BaseObject, visitor.Navigation);
return (IQueryable<T>)query;
}
public static int Count<T>(this DbContext context, Expression<Func<IEnumerable<T>>> expression) =>
AsQueryable(context, expression)?.Count() ?? 0;
Enabling strongly typed usage like the following;
public int TotalStudents(DbContext context) =>
context.Count(() => this.Students);
public int ActiveStudents(DbContext context) =>
context.AsQueryable(() => this.Students)?.Where(s => s.Active).Count() ?? 0;

How do I call a method from another solution to create a sort of data wrapper?

I have a simple class for pulling data from a database that is linked to the ADO framework or whatever called OperationsEntities...
namespace DataModel
{
public class PublisherData
{
public static List<Publisher> GetByID(int n)
{
using (OperationsEntities context = new OperationsEntities())
{
var query = from results in context.Publishers
where results.id == n
select results;
List<Publisher> list = query.ToList<Publisher>();
return list;
}
}
public static List<Publisher> GetByName(string s)
{
using (OperationsEntities context = new OperationsEntities())
{
var query = from results in context.Publishers
where results.contact_name == s
select results;
List<Publisher> list = query.ToList<Publisher>();
return list;
}
}
}
}
Now, I'm trying to create a datawrapper in a business tier solution to pass this data from the data layer to the form layer (to make things nice and modular, and allow us to change the form layer to an online .NET app in the future, if we so desire, without having to rewrite everything.)
However, I can't seem to figure out how to use the GetByID and GetByName methods in my other class. I have the reference to my DataModel in my BusinessLogic namespace, and have "using DataModel;" at the top of my DataWrapper.cs.
I'm also struggling over the best way to handle the results. So far I'm trying to basically create a duplicate class of that on the DataModel that will just parse them out into a new class. So far, the skeleton for it is this...
namespace BusinessLogic
{
class PublisherWrapper
{
int id;
string publisherName;
string address;
string city;
string state;
string zip;
string contact_name;
string contact_phone;
List<PublisherWrapper> list;
public PublisherWrapper() { }
public static List<PublisherWrapper> GetListByID(int n)
{
List<Publisher> list = new List<Publisher>();
}
return list;
}
}
Any time I try to call the DataModel static methods it gives me the red squiggly of some kind of error, but doesn't provide any further information. Why can't I call those public static methods in my BusinessLogic solution?
Try making your PublisherData class static. Also does your DataModel project currently build?

Creating common class objects based on class name and use it

I have the same code logic used across different class objects.
For ex:
var matchingTypes = from matchType in order.Contacts
select matchType;
var matchingTypes = from matchType in customer.Contacts
select matchType;
Instead of writing duplicate lines of code, i would like to pass order, customer class names and get Contacts through it, so that the above code will look like (we are using LINQ in our code)
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
The stuff i tried is passed an object parameter
GetData(object objectElement) // method consuming an object parameter.
var objectOrder= objectElement as Orders;
var objectCustomer= objectElement as Customers;
if(objectOrder!=null)
{
objectElement = (Orders) objectOrder; //type
}
if(objectCustomer !=null)
{
objectElement = (Customers) objectCustomer;
}
By doing so, i am repeating my code, which i would like to avoid, any suggestions/ideas? thanks.
I would like to use objectElement and assign only once, so that i can call like this as shown below
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
An interface would be the preferred way to do this, but you could also use dynamic to duck type a method:
public IEnumerable<Contact> GetContacts(dynamic yourObject)
{
return yourObject.Contacts;
}
Note this will not give you a compile error if you call it with something that doesn't have a property called Contacts of type IEnumerable<Contact> but will instead give you a runtime error.
Or you don't even actually need a method, you could just do this:
var matchedTypes = ((dynamic)yourObject).Contacts as IEnumerable<Contact>;
Interfaces would be a safer bet, but are a little tricky with generate entity framework classes. But you can do them becuase they are generated as partial classes. So you can do something like this:
public interface IHaveContacts
{
public IEnumerable<Contact> Contacts { get; }
}
and then:
public partial class Orders : IHaveContacts
{
// should need to do anything since the auto-genrated Contacts property
// will satisfy the interface
}
public partial class Customers : IHaveContacts
{
// ditto
}
And now you can do:
var matchedTypes = ((IHaveContacts)yourObject).Contacts;
Or, if you really, really must (which you don't):
var matchedTypes = from matchType in ((IHaveContacts)yourObject).Contacts
select matchType;
Create an interface IContactsContainer:
public interface IContactsContainer
{
public YourContactType Contacts{get;set;}
}
Then your customer and order classes can implement it:
public class Customers : IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
public class Orders: IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
After that in your method you can use:
IContactsContainer objectElement = yourOrderObject;

Using LINQ with wrapped arrays

I'm new to LINQ and I'm doing a simple project to learn the features of the technology.
Currently I've got a static class that wraps an array of object (a kind of simple factory). Let's say it looks like the following:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
// ...
}
Now I can add some functions to my Factory that allow me to query the inner array, e.g.
public static Item GetByID(ItemID id)
{
var query =
from item in items
where item.ID == id
select item;
return query.First();
}
However, this requires me to modify the internals of the Factory class. Is there a way to write such queries from the 'outer world' instead ?
public class OtherClass
{
var result = from it in Factory select ...
}
?
Yes, you can. Just use linq on the Factory from the 'outer world':
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Items.SingleOrDefault(i => i.ID == id);
}
}
Of course, to do this, you'd need to change the access modifier of the items array to be public.
There are so many options.
The easiest thing to do is just to expose a public property that allows just what you want to have allowed:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
public static IEnumerable<IReadableItem> Items{ get { return items; } }
// ...
}
The above code assumes that the Item class implements an IReadableItem interface that only has the methods and properties on it that you want to allow people to access. You could also clone the items list before returning it each time, if you're worried someone might re-cast the Items or try to modify it using reflection. Because the standard LINQ methods all work off of IEnumerable<>s, this would allow someone to effectively produce a LINQ query on your items, without exposing overmuch data.
List<string> bestItemNames = Factory.Items.Where(i => i.IsBest)
.Select(i => i.Name)
.ToList();
If you wanted to get really fancy, you could even implement your own LINQ provider. From a language perspective, LINQ expression syntax just maps to specific method names, so if you had a class that implemented a .Where() and a .Select() method, then you could implement that pretty much however you wanted, and people wouldn't know any different until they tried doing something that your methods didn't support.
One possibility is to implement IQueryable<T> for a non-static class:
public class Factory<T> : IQueryable<T>
{
protected T[] _items = new T[]{};
public Type ElementType
{
// or typeof(T)
get { return _items.AsQueryable().ElementType; }
}
public System.Linq.Expressions.Expression Expression
{
get { return _items.AsQueryable().Expression; }
}
public IQueryProvider Provider
{
get { return _items.AsQueryable().Provider; }
}
public IEnumerator<T> GetEnumerator()
{
return ( IEnumerator<T> )_items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
}
Derive non-generic class to populate array (if desired)
public class ItemFactory : Factory<Item>
{
public ItemFactory()
{
// items are created here
}
}
Create static instance
public static class Factories
{
private static ItemFactory _itemFactory = new ItemFactory();
public static ItemFactory ItemFactory { get { return _itemFactory; } }
}
Usage:
var specificItem = Factories.ItemFactory
.Where( item => item.ID == id )
.SingleOrDefault();
use an expression tree
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Get(i => i.id == id);
}
}
and change the get method to
public Item Get(Expression<Func<Item,bool>> filter)
{
return items.SingleOrDefault(filter);
}
however, this approach makes little sense unless you are encapsulating some other logic in your factory class i.e. select only rows that are not soft deleted.

Best Way To Filtering Child Entities In Entity Framework

I am not deleting entities. I just sign them by IsDeleted property. The problem is when I get a parent element, its all child elements are loaded even if IsDeleted propery is true or false. Then I did something like below, but I want to know is there a better way to do it ?
var result = from p in context.Set<Product>().Include(x => x.Reviews)
select new
{
Product = x,
ProductReviews = x.ProductReviews.Where(y => !y.IsDeleted)
};
var products = new List<Product>();
foreach (var product in result.OrderBy(x => x.Product.Id).Skip(skipRecords).Take(pageSize))
{
var p = new Product();
p = product.Product;
p.ProductReviews = product.ProductReviews.ToList();
products.Add(p);
}
return products;
How to improve this code block ?
Thanks
What I did to address this type of situation before was to create a specific interface signifying the classes that are "flag deleted" like this and then create an Extension Method that filters them out.
If you only have one class with the IsDeleted property, then you don't need a separate interface and you can just use the class instead. But I'll assume for the moment that you do have multiple classes and that the interface is needed.
So the interface would be defined like so:
public interface IHaveIsDeleted
{
public bool IsDeleted { get; set; }
}
Then my Extension Method would be defined in a static class like so:
public static class MyExtensionMethods
{
public IQueryable<T> FilterDeleted(this IQueryable<T> src) where T : IHaveIsDeleted
{
return src.Where(x => !x.IsDeleted);
}
}
Because this is done on an IQueryable<T>, the where clause gets built into the query that is sent to the database, so there won't be any records returned where IsDeleted is true. So all you would have to do in your example is call x.ProductReviews.FilterDeleted().
Now, the project that I was using this method in was actually using LINQ2SQL. And I'm rather new to EF myself, so there might be a more 'EF specific' way of doing this, (like perhaps some kind of Type Per Hierarchy construct, maybe?), but I just thought this would at least help make your queries simpler.
Hope that helps! ;)

Categories