In Part-1 of this post I explained language translation via <QueryView> and Entity Join approach that is suggested for scenario having just one translation table. This article present a generic approach that can be used with multiple translation tables
Problem :-
Lets assume you have a Product Entity and and it has one fields that need to be translated. For simplicity I am Just using one table. Step by step solution is below
Solution
- Create your Main Table in EDMX and add the additional property (Translated Name)
- Also import all the translation tables
- In order support additional property you either you need <DefiningQuery> or <QueryView> element to explicitly supply select query. This solution uses <QueryView>. See additional Null in query view.
<EntitySetMapping Name="Products">
<QueryView>
select value
NORTHWNDModel.Product
(p.ProductID,
p.ProductName,
null,
p.SupplierID,
p.CategoryID,
p.QuantityPerUnit,
p.UnitPrice,
p.UnitsInStock,
p.UnitsOnOrder,
p.ReorderLevel,
p.Discontinued
)
from
NORTHWNDModelStoreContainer.Products
as p
</QueryView>
</EntitySetMapping>
|
- Override "OnStartProcessingRequest" in data service class
protected override void OnStartProcessingRequest(ProcessRequestArgs args)
{
this.CurrentDataSource.ObjectMaterialized
+= new System.Data.Objects.ObjectMaterializedEventHandler(CurrentDataSource_ObjectMaterialized);
base.OnStartProcessingRequest(args);
}
|
- Implement ObjectMaterialized even to do actual translation
void
CurrentDataSource_ObjectMaterialized(object
sender, System.Data.Objects.ObjectMaterializedEventArgs
e)
{
//This code uses hardecoded language parameter but if you want to pass it
// dynamicly use query paramteters
string
language = "IT-IT";
var
entities = this.CurrentDataSource;
if
(e.Entity.GetType() == typeof(Product))
{
Product
entity = (Product)e.Entity;
var
translation = from code in entities.NameTranslations
where (entity.ProductID==code.ProductID &&
code.Language == language)
select code;
if
(translation.Count()>0)
{
entity.ProductTranslatedName = translation.First().ProductNativeName;
}
else
{
entity.ProductTranslatedName = "Not
Found";
}
}
}
|
Navigate to your service URL to see the result
-<m:properties>
<d:ProductID
m:type="Edm.Int32">1</d:ProductID>
<d:ProductName>Chai</d:ProductName>
<d:ProductTranslatedName xml:space="preserve">IT_Chai</d:ProductTranslatedName>
<d:SupplierID
m:type="Edm.Int32">1</d:SupplierID>
<d:CategoryID
m:type="Edm.Int32">1</d:CategoryID>
<d:QuantityPerUnit>10 boxes x 20 bags</d:QuantityPerUnit>
<d:UnitPrice
m:type="Edm.Decimal">18.0000</d:UnitPrice>
<d:UnitsInStock
m:type="Edm.Int16">39</d:UnitsInStock>
<d:UnitsOnOrder
m:type="Edm.Int16">0</d:UnitsOnOrder>
<d:ReorderLevel
m:type="Edm.Int16">10</d:ReorderLevel>
<d:Discontinued
m:type="Edm.Boolean">false</d:Discontinued>
</m:properties>
<d:ProductID m:type="Edm.Int32">3</d:ProductID>
<d:ProductName>Aniseed Syrup</d:ProductName>
<d:ProductTranslatedName>Not Found</d:ProductTranslatedName>
<d:SupplierID m:type="Edm.Int32">1</d:SupplierID>
<d:CategoryID m:type="Edm.Int32">2</d:CategoryID>
<d:QuantityPerUnit>12 - 550 ml bottles</d:QuantityPerUnit>
<d:UnitPrice m:type="Edm.Decimal">10.0000</d:UnitPrice>
<d:UnitsInStock m:type="Edm.Int16">13</d:UnitsInStock>
<d:UnitsOnOrder m:type="Edm.Int16">70</d:UnitsOnOrder>
<d:ReorderLevel m:type="Edm.Int16">25</d:ReorderLevel>
<d:Discontinued m:type="Edm.Boolean">false</d:Discontinued>
</m:properties> |
Suggested
- Extract Language parameter dynamically.
- Querying database for each row in "CurrentDataSource_ObjectMaterialized" handler could be a big performance hit especially in case of large tables. I would suggest to implement caching of entire translation table at once. I will try to post another article on it once I have time.
Limitation
- This approach will not work on projection ($select) query
- Filter ($filter) will not work correctly on translated property
No comments:
Post a Comment