我是c#的新手,现在对Generics和Entity Framework感到困惑。我在数据库中有两个表,我使用Entity Framework在我的代码中检索。在我的aspx页面上,我有一个网格,应根据用户选择的表填充数据。
将来会有更多的桌子。所以我想写一个工厂模式来获取datagrid的源列表。我不能让它工作,因为我很困惑。
这是我的BaseClass和两个子类的代码。
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();
}
}
有人可以相应地更正代码吗?我必须在这里使用泛型吗?我尝试在BaseClass中使用它,但它无法正常工作,因为我必须相应地修复我的子类,对此我没有任何线索。
答案 0 :(得分:0)
答案 1 :(得分:0)
首先,使用泛型,您可以编写更易读,更简短的代码。 我认为最好不要将工厂类用于存储库,最后您需要知道在代码中处理它的类型,例如:
Child1 report = new Child1();
report.SomeBehaviorInChild1(); // this is not achievable with base class.
如果您想使用此工厂,您可以执行以下操作: ReportBase report = Factory.GetReport();
其次,将您的列表公开是一个坏主意,因为您不希望那些使用您的类的人从他们的代码创建新列表,例如: report._list = new List(); 你不希望这件事发生在你班级的对象中。因此,最好将列表设为私有,并且仅依赖于返回报表数据源的方法。 私人名单_list;
public List<T> GetDataSource()
{
return _list;
}
第三,如果你实现了一个通用报告库,你就不需要编写子类,除非它们有一些特殊的基础没有实现。 第四,Filter方法的当前实现太糟糕了,因为你在这里做的是从数据库获取所有记录,然后在内存中过滤它们。这种实现是一种不好的做法。更好的方法是使用IQueryable,它是一个被保护的执行对象,即在您提出请求之前不会填充结果。
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;
}
所以这是解决问题的更好方法。我认为你读一本名为“#34;更有效的C#2008&#34;它总体上讨论了queryable和linq。 现在,如果我们在BaseReportClass上应用它,我们可以得到以下内容:
//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;
}
}
现在定义子类的附加行为。
//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();
}
}
这是使用您的类的代码:
Child1 report = new Child1(new GetChild1Entities());
report.FilterOnStartDate(DateTime.Now);
希望这很有用。