我想知道使用實體框架和linq創建動態查詢的最佳方式是什麼。使用實體框架創建動態查詢
我想創建一個具有許多排序和過濾參數(超過50)的服務。我將從gui中獲得這些對象的填充內容,並且將從單個服務方法執行查詢。
我環顧四周我看到我可以動態創建一個字符串,可以在我的方法結束時執行。我不太喜歡這種方式。有一個更好的方法嗎?最好使用編譯檢查鍵入safe?
我想知道使用實體框架和linq創建動態查詢的最佳方式是什麼。使用實體框架創建動態查詢
我想創建一個具有許多排序和過濾參數(超過50)的服務。我將從gui中獲得這些對象的填充內容,並且將從單個服務方法執行查詢。
我環顧四周我看到我可以動態創建一個字符串,可以在我的方法結束時執行。我不太喜歡這種方式。有一個更好的方法嗎?最好使用編譯檢查鍵入safe?
你可以一步一步撰寫IQueryable<T>
。假設你有一個FilterDefinition
類,它描述了用戶希望如何過濾...
public class FilterDefinition
{
public bool FilterByName { get; set; }
public string NameFrom { get; set; }
public string NameTo { get; set; }
public bool FilterByQuantity { get; set; }
public double QuantityFrom { get; set; }
public double QuantityTo { get; set; }
}
...那麼你可以創建一個查詢,像這樣:
public IQueryable<SomeEntity> GetQuery(FilterDefinition filter)
{
IQueryable<SomeEntity> query = context.Set<SomeEntity>();
// assuming that you return all records when nothing is specified in the filter
if (filter.FilterByName)
query = query.Where(t =>
t.Name >= filter.NameFrom && t.Name <= filter.NameTo);
if (filter.FilterByQuantity)
query = query.Where(t =>
t.Quantity >= filter.QuantityFrom && t.Quantity <= filter.QuantityTo);
return query;
}
您可以考慮使用WCF數據服務創建服務並動態創建URI以查詢您的實體模型。
我知道的唯一另外一種方法是根據您的過濾器構建一個IQueryable。
public List<Contact> Get(FilterValues filter)
{
using (var context = new AdventureWorksEntities())
{
IQueryable<Contact> query = context.Contacts.Where(c => c.ModifiedDate > DateTime.Now);
if (!string.IsNullOrEmpty(filter.FirstName))
{
query = query.Where(c => c.FirstName == filter.FirstName);
}
if (!string.IsNullOrEmpty(filter.LastName))
{
query = query.Where(c => c.LastName == filter.LastName);
}
return query.ToList();
}
}
是的,但這是有效的表現明智嗎?選擇何時執行?到底什麼時候ToList()被調用?想象一下,我有非常大的數據集...... – Eduard 2011-04-05 06:38:20
不,這不是性能問題,因爲它使用延遲執行來只查詢一次。 – BrandonZeider 2011-04-05 12:54:02
+1謝謝你的回答。 – Eduard 2011-04-05 14:05:08
您可以使用動態的規範和動態排序。我已經對他們的博客here和here。下面的例子應該可以幫助你 -
//Assume you're getting following values from search form.
string userSuppliedProperty = "AverageRating";
OperationType userSuppliedOperationType = OperationType.GreaterThan;
var userSuppliedValue = 4.5;
//Create DynamicSpecification from these properties and pass it to repository.
var userFilter = new DynamicSpecification<Product>(userSuppliedProperty, userSuppliedOperationType, userSuppliedValue);
var filteredProducts = _repository.Get(userFilter);
//You can also combine two specifications using either And or Or operation
string userSuppliedProperty2 = "Category";
OperationType userSuppliedOperationType2 = OperationType.EqualTo;
var userSuppliedValue2 = "Keyboard";
var userFilter2 = new DynamicSpecification<Product>(userSuppliedProperty2, userSuppliedOperationType2, userSuppliedValue2);
var combinedFilter = userFilter.And(userFilter2);
var filteredProducts2 = _repository.Get(combinedFilter);
//and it support dynamic sorting
string userSuppliedOrderingProperty = "Category";
OrderType userSuppliedOrderType = OrderType.Ascending;
var sortedFilteredProducts = _repository.Get(combinedFilter, o => o.InOrderOf(userSuppliedOrderingProperty, userSuppliedOrderType));
我不知道搜索對象/ DTO你得到,但你可以很容易地創建一個通用搜索對象/ DTO,並可以將其映射到幾行GenericSpecification的對象鏈的代碼。過去我曾經使用過WCF服務,它對我來說工作得非常好。
謝謝,但是這個工作怎麼樣?這不是從數據庫中提取所有數據,然後逐步縮小到所需的一組數據? – Eduard 2011-04-05 06:36:52
@ t-edd:不,它利用「延遲執行」(http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx)。這意味着在上面的例子中構成的'IQueryable'只是一個描述數據如何過濾的查詢表達式。查詢的真正執行完全不在本例中。您執行查詢,然後通過將「貪婪」運算符應用於'IQueryable ',例如'query.ToList()'。此時 - 而不是更早 - 查詢表達式被翻譯成SQL併發送到服務器。 –
Slauma
2011-04-05 10:03:21
這不是很好,因爲它假設'SomeEntity'具有名稱和數量字段,所以這只是一半的動態。 – 2017-01-23 17:56:57