[英]C# Generic binding
我正在為學校分配作業,並嘗試為學習而實現盡可能多的功能。 因此,我做了一個通用的映射器,將數據庫表映射到對象,以查看可能的情況。 在這種情況下,Db是本地的。 我知道我要處理大量的呼叫,應該以不同的方式解決這個問題,但是...
一切都按預期工作,但當一個類具有另一個類的Collection時除外。
例:
class Student {
public int Id { get; set; }
public string Name { get; set; }
}
我的方法用於填充數據庫中所有學生的列表。
public List<TModel> MapEntitiesFromDb<TModel>(string tablename, string customquery = "") where TModel : class, new()
{
try
{
sql = ValidateSelectSql(tablename, customquery);
}
catch (AccessViolationException ex) { Console.WriteLine(ex.Message); }
command.CommandText = sql;
command.Connection = conn;
List<TModel> list = new List<TModel>();
try
{
using (conn)
{
Type t = new TModel().GetType();
conn.Open();
using (reader = command.ExecuteReader())
{
if (t.GetProperties().Length != reader.FieldCount)
throw new Exception("There is a mismatch between the amount of properties and the database columns. Please check the input code and try again.");
//Possible check is to store each column and property name in arrays and match them to a new boolean array, if there's 1 false throw an exception.
string columnname;
string propertyname;
//Pairing properties with columns
while (reader.Read())
{
TModel obj = new TModel();
for (int i = 0; i < reader.FieldCount; i++)
{
columnname = reader.GetName(i).ToString().ToLower();
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo propertyinfo in properties)
{
propertyname = propertyinfo.Name.ToLower();
if (propertyname == columnname)
{
propertyinfo.SetValue(obj, reader.GetValue(i));
break;
}
}
}
list.Add(obj);
}
}
}
}
catch (Exception ex) { Console.WriteLine(ex.Message); }
return list;
}
我的ValidateSelectSql只是返回查詢中需要使用的sql字符串。
致電后:
List<Student> = MapEntitiesFromDb<Student>("students");
它將返回一個列表,其中包含所有想要的學生。
例如,當我添加一個集合時,事情就出錯了:
class Student {
public Student()
{
this.Courses = new List<Course>();
string customsqlquery = ::: this works and is tested! :::
Courses = MapEntitiesFromDb<Course>("", customsqlquery);
}
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Course> Courses;
}
課程列表返回為空,並且在我創建對象時發現的調試器工具的幫助下,Id屬性當然為0。 在我的查詢中,我正在過濾學生ID,但是在執行將方法填充到構造函數中的“課程”列表時,該學生的ID始終為0,因為它是在稍后階段設置的,結果將是該列表中沒有課程。
我想知道是否應該在設置其他屬性后檢查ICollection屬性,是否在對象上執行一個方法,然后返回執行構造函數內部的方法?
我不能在TModel上調用任何方法,否則就像找到TModel是否具有collection屬性並調用obj.FillCollection()一樣簡單。 在GetEntitiesFromDb方法中分配Id屬性之后。
我也在考慮遞歸。 再次,我必須查找obj是否具有collection屬性,然后調用GetEntitiesFromDB,但這似乎是不可撤消的,因為我還需要找出<>之間的類型,並且我無法從外部發送任何customquery ...
也許是從另一個角度解決呢?
我真的可以就如何解決這個問題使用一些建議。
解決此問題的最直接方法是讓collection屬性延遲加載所需的內容。 我還建議您使用IEnumerable<T>
而不是ICollection<T>
因為這表示數據庫中當前內容的只讀視圖,沒有人可以任何方式對其進行修改。
public class Student
{
private readonly Lazy<IEnumerable<Course>> courses;
public int Id { get; set; }
public IEnumerable<Course> Courses => this.courses.Value;
public Student()
{
this.courses = new Lazy<IEnumerable<Course>>(LoadCourses);
}
private IEnumerable<Course> LoadCourses()
{
var sql = "custom SQL query that uses this.Id after it's loaded";
return MapEntitiesFromDb(sql);
}
}
我只推薦這種方法,因為您提到這只是一個學術練習,可以幫助您了解可用的工具。 在實際的生產環境中,這種方法很快就會變得笨拙,我建議改用Entity Framework(這可能是您可能想了解的其他東西)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.