我遇到了物體框架 6 的問題,我不知道如何解決。我想從帶有 EntityFramework 的表中讀取資料。目標是使用 where 子句讀取該資料,該子句從特定列中過濾資料。我要搜索的列在方法引數中指定。
一個例子:我有一張人表
| 名稱 | 名 | 地址 | 電子郵件 |
|---|---|---|---|
| 康納 | 布賴恩 | 紐約 | [email protected] |
| 施瓦辛格 | 阿諾德 | 洛杉磯 | [email protected] |
通常我會選擇這樣的資料:
public List<Person> getData(string searchTerm)
{
using (var db = new myDB())
{
return db.Person.Where(x=> x.Name == searchTerm).ToList();
}
}
但我也想靈活處理我想過濾的列。像這樣的東西:
public getData(string columnToSearch, string searchTerm)
{
using (var db = new myDB())
{
return db.Person.Where(columnToSearch == searchTerm).ToList();
}
}
我怎樣才能做到這一點?
我不想使用普通 SQL 并且我無法編輯資料庫。
感謝您的幫助。
uj5u.com熱心網友回復:
鑒于您只有 4 列,我真的認為我只是:
public List<Person> GetData(string columnToSearch, string searchTerm)
{
using var db = new myDB();
if(columnToSearch == "Name")
return db.Person.Where(p => p.Name == searchTerm).ToList();
else if(columnToSearch == "FirstName")
return db.Person.Where(p => p.FirstName == searchTerm).ToList();
else if(columnToSearch == "Adress")
return db.Person.Where(p => p.Adress == searchTerm).ToList();
else if(columnToSearch == "Email")
return db.Person.Where(p => p.Email == searchTerm).ToList();
else
throw ..
}
..或一些類似的選擇結構..
public List<Person> GetData(string columnToSearch, string searchTerm)
{
using var db = new myDB();
return (columnToSearch switch {
"Name" => db.Person.Where(p => p.Name == searchTerm),
"FirstName" => db.Person.Where(p => p.FirstName == searchTerm)
"Adress" => db.Person.Where(p => p.Adress == searchTerm)
"Email" => db.Person.Where(p => p.Email == searchTerm)
_ => throw new ArgumentException(nameof(columnToSearch) " should be one of: Name, FirstName, Adress, Email")
}).ToList();
}
..甚至可以切換進行采摘的委托:
public List<Person> GetData(string columnToSearch, string searchTerm)
{
Func<Person, bool> what = columnToSearch switch {
"Name" => p => p.Name == searchTerm,
"FirstName" => p => p.FirstName == searchTerm
"Adress" => p => p.Adress == searchTerm
"Email" => p => p.Email == searchTerm
_ => throw new ArgumentException(nameof(columnToSearch) " should be one of: Name, FirstName, Adress, Email")
};
using var db = new myDB();
return db..Person.Where(what).ToList();
}
即使您在此表中有 20 列,使用多行編輯器撰寫這樣的重復代碼也相當容易:

那是一個名為 Sublime 的編輯器,但 VS 也可以這樣做,要么使用ctrl alt click 放置多個游標,要么選擇一些常見的東西并按下shift alt .。如果您使用 VS,您將需要安裝“Multiple Caret Booster”擴展,否則粘貼會很瘋狂;在大多數執行多個插入符號的編輯器中,如果您有例如 20 個插入符號并從剪貼板粘貼 20 行(例如 20 個列名稱),則每個插入符號將獲得一個剪切行。通常在 VS 中,每個插入符號都會獲得所有 20 行(粘貼了 400 行),這使得將所有 20 列都放在剪貼板上并將它們粘貼到代碼流中非常困難,就像上面的影片一樣
uj5u.com熱心網友回復:
您可以使用以下擴展方法:
public static class QueryableExtensions
{
public static IQueryable<T> FilterByColumn<T>(this IQueryable<T> query, string columnToSearch, string searchTerm)
{
var param = Expression.Parameter(typeof(T), "e");
var body = Expression.Equal(
Expression.PropertyOrField(param, columnToSearch),
Expression.Constatnt(searchTerm));
var filter = Expression.Lambda<Func<T, bool>>(body, param);
return query.Where(filter);
}
}
和用法:
public getData(string columnToSearch, string searchTerm)
{
using (var db = new myDB())
{
return db.Person.FilterByColumn(columnToSearch, earchTerm).ToList();
}
}
uj5u.com熱心網友回復:
您正在使用物體框架,它可以訪問您的Persons. 您可能有一個DbContext具有訪問此表的屬性:
public DbSet<Person> Persons {get; set;}
你也有兩個字串。一個字串表示Person要過濾的屬性的名稱,另一個字串表示該屬性應具有的值。
為了使您的代碼更易于閱讀、更易于重用、更易于維護和單元測驗,我的建議是將您的問題分成兩個子問題:
- 將字串
columnToSearch(實際上是您要搜索的列的名稱)轉換為 propertySelector,類似于 GroupBy 中的 keySelector。 - 創建一個使用此 KeySelector 選擇屬性的擴展方法,并使用
searchTerm和Where僅保留Persons具有相同值的那些。
這種分離的好處在于,您可以在訪問資料庫之前檢測 columnToSearch 的錯誤值。如果您不想支持某些屬性,例如外鍵,則可以將它們排除在外。該方法易于理解,易于重用,易于單元測驗,并且易于更改,例如如果您想添加一個新列。
Expression<Func<Person, string>> ToPropertySelector(string columnName)
{
switch (columName)
{
case nameof(Person.Name):
return person => person.Name;
case nameof(Person.FirstName):
return person => person.FirstName;
...
default: // unsupported columnName
throw new InvalidArgumentException(...);
}
}
如果您的列有其他名稱而不是您想要與用戶交流LastName的名稱,例如,如果外部使用 think of而不是名稱,您可以輕松更改程序:
case "Name":
case "LastName":
return person => person.Name;
此外,如果稍后列名稱更改,外部用戶將不必更改。
用法:
string columName = "Email";
string value = "MyName.Gmail.Com";
using (var dbContext = new MyDbContext(...))
{
var propertySelector = ToPropertySelector(columnName);
return dbContext.Persons
.Where(person => propertySelector(person) == value)
.ToList();
}
當然,這僅在您的屬性將字串作為值時才有效。如果您還想支持其他屬性型別,則需要創建一個具有正確型別的擴展方法:
Expression<Func<Person, TProperty>> ToPropertySelector<TProperty>(string columnName)
{
... see above
}
public static IQueryable<Person> Where<TProperty>(IQueryable<Person> persons,
string columName,
TProperty value)
{
var propertySelector = ToPropertySelector<TProperty>(columnName);
return persons.Where(person => propertySelector(person) == value);
}
public static IQueryable<Person> Where<TProperty>(IQueryable<Person> persons,
string columName,
string valueTxt)
{
Type propertyType = typeof(TProperty);
TypeConverter converter = propertyType.GetConverter();
TProperty value = converter.ConvertFromString(valueTxt)
return persons.Where(columnName, value);
}
用法:
DateTime birthDay = new DateTime(1993, 11, 23);
IQueryable<Person> persons = ...
var personsBornOnDate = persons.Where("BirthDay", birthDay);
重用示例:您不必使用 BirthDay 作為字串,您可以使用屬性選擇器:
var personsBornOnDate = persons.Where(person => person.BirthDay, birthDay);
后者的好處是,如果您使用不存在的屬性,編譯器會警告您。字串版本只會在運行時警告您。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/393674.html
