我覺得我問了很多問題,但我一直陷入困境。我正在開發一個OData服務,並且我想要一個可以有多個用戶指定的名稱 - 值對關聯的實體,然後可以對其進行搜索。我正在使用EF4.3,DataServiceVersion 3.0。我正在使用自定義的元數據,查詢和更新提供程序。用繼承實體過濾OData請求導致鑄造異常
所以我們可以說,我有一個實體的人:(EntityBase是一種常見的POCO,我所有的實體來自;它只有一個GUID ID屬性)
public class Person : EntityBase
{
public virtual IList<Property> PropertySet { get; set; }
}
現在讓我們來定義屬性:
public abstract class Property : EntityBase
{
public string Name { get; set; }
public Person Person { get; set; }
public Guid PersonId { get; set; }
}
public class IntProperty : Property
{
public int? IValue { get; set; }
}
public class StringProperty : Property
{
public string SValue { get; set; }
}
到目前爲止,這麼好。在我的配置中,我使用Table Per Hierarchy來進行繼承。
現在,我可以將屬性添加到我的人,當我提出這樣的要求:
GET /Service/People(guid'THE_ID')?$expand=PropertySet
它的工作原理:
{"d": {
"__metadata": {...},
"PropertySet": {
"results": [{
"__metadata": {...},
"Id": "PROP_1_ID",
"Name": "Number",
"IValue": 1234
},{
"__metadata": {...},
"Id": "PROP_2_ID",
"Name": "EmailAddress",
"SValue": "AAAA"
}]
},
"Id": "THE_ID",
}
}
如果我查詢一個人說有一個名爲'EmailAddress'的屬性,它的工作原理如下:
GET /Service/People?$expand=PropertySet&$filter=PropertySet/any(x: x/Name eq 'EmailAddress')
但即便如此,我還得拉幾個竅門。我實現了一個表達式遊客和重擊了幾個比較是LINQ到實體似乎並不喜歡:
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType == ExpressionType.Equal)
{
Expression left = Visit(node.Left);
Expression right = Visit(node.Right);
ConstantExpression rightConstant = right as ConstantExpression;
if (null != rightConstant && rightConstant.Value == null)
{
if (left.Type == typeof(IList<Property>))
{
return Expression.Constant(false, typeof(bool));
}
}
}
return base.VisitBinary(node);
}
protected override Expression VisitConditional(ConditionalExpression node)
{
Expression visitedTest = Visit(node.Test);
Expression visitedIfTrue = Visit(node.IfTrue);
Expression visitedIfFalse = Visit(node.IfFalse);
ConstantExpression constantTest = visitedTest as ConstantExpression;
if (null != constantTest && constantTest.Value is bool)
{
return ((bool)constantTest.Value) ? visitedIfTrue : visitedIfFalse;
}
return Expression.Condition(visitedTest, visitedIfTrue, visitedIfFalse);
}
要點是與第一重寫我的查詢獲取諸如「it.PropertySet == NULL 「,我知道這將永遠是不真實的。 (在我的秒殺中,唯一有PropertySet的是Person,而Person總是有一個PropertySet。)在第二個覆蓋中,我正在查看諸如「IIF((it.PropertySet == null),Empty (),it.PropertySet)「,我知道」it「將始終有一個PropertySet。這可以防止將IList與null進行比較的錯誤。
現在,問題所在。
僅僅尋找物業的存在是不夠的。我想檢查它的值:
GET /Service/People?$expand=PropertySet&$filter=PropertySet/any(x: x/Name eq 'EmailAddress' and cast(x, 'InheritedPropertyTest.Entities.StringProperty')/SValue eq 'AAAA')
這是結果查詢:
value(System.Data.Objects.ObjectQuery`1[InheritedPropertyTest.Entities.Person])
.MergeAs(AppendOnly)
.Where(it => it.PropertySet.Any(x => ((x.Name == "EmailAddress") AndAlso (IIF((Convert(x) == null), null, Convert(x).SValue) == "AAAA"))))
.OrderBy(p => p.Id)
.Take(100)
.Select(p => new ExpandedWrapper`2() {ExpandedElement = p, Description = "PropertySet", ReferenceDescription = "", ProjectedProperty0 = p.PropertySet.OrderBy(p => p.Id) .Take(100)})
但我得到這個錯誤:「無法轉換類型‘InheritedPropertyTest.Entities.Property’到類型'InheritedPropertyTest.Entities.StringProperty'。LINQ to Entities只支持投射實體數據模型原語類型。「所以...現在我卡住了我的頭靠牆再次。也許我的繼承設置不正確?我是否需要重載一些其他Expression Visitor方法來進行Convert工作?我如何說服Linq To Entities使用繼承的屬性?
謝謝!
嗯,我試過了,它的工作完美無瑕。我從來沒有見過這種語法,謝謝! 至於自定義提供程序的東西...是的,這是棘手的,但我們迄今做得很好。正是這種繼承和開放式的東西讓我頭痛不已。我認爲我們由於某種原因打開了空傳播,但現在我不記得了,應該重新審視它。我想,取消空值支票是一個小的代價。 再次感謝您的協助! – object88