ObjectSet<entityA> entityAs;
But I need an ObjectResult<entityB>, and has created this (custom) property on ObjectContext:
ObjectResult<entityB> entityBs
{ ... }
So when I user entityBs as QueryName in RadEntityFrameWorkDataSource (in XAML), then nearly all works fine except AddNew, because the QueryName is used for getting ObjectResult<> property value of ObjectContext, and for entitySetName.
Can I somehow enforce the real base entit class's set name for use as entitySetName, and (any) ObjectQuery as object query used to create QueryabelEntityCollection?
It is not a solution, when I use for QueryName the base ObjectSet's name (and approperiate FilterDescription), because the AddNew produce a base class instance not a derived class's one.
(ok, I can create manually QueryabelEntityCollection<entityB>, but it is not real beuty solution :))
11 Answers, 1 is accepted
I am afraid that we will significantly mess up the public API of RadEntityFrameworkDataSource if we add yet another property besides the QueryName.
Anyway, the control is simply a very thin wrapper over QueryableEntityCollectionView<T>, so my suggestion would be to use this collection if possible.
Thank you for your understanding.
Ross
the Telerik team
I think does not need implement any plus property. In RadEntityFrameworkDataSource's TryRefreshView method can get all need info, like this (entityType is get in TryRefreshView):
Type typeParent = entityType;
while (typeParent != null || typeParent.BaseType != typeof(EntityObject))
typeParent = typeParent.BaseType;
if (typeParent == null)
; //exception, targettype is not EntityObject
Type osetType = typeof(ObjectQuery<>).MakeGenericType(new Type[] {typeParent});
var esv = from PropertyInfo pi in objectQuery.GetProperties()
where pi.PropertyType.IsSubclassOf(osetType)
select pi;
ObjectQuery oquery = esv.First().GetValue(ObjectContext , null) as ObjectQuery;
System.Data.Metadata.Edm.EntitySet es = oquery.GetType().GetProperty("EntitySet").GetValue(oquery, null) as System.Data.Metadata.Edm.EntitySet;
string realqueryname = es.Name;
In realqueryname we can found the queryname of top parent class's query name, so can use it in QueryableCollection view instance creation.
And when the ObjectQueryProxy's Add method will be called, then the right entitySetName will be used.
And of course the code like above can be place into an if (entityType.BaseType != typeof(EntityObject))
blokk, and all the usage of RadEntityFrameworkDataSource worked before will be work after same way.
K2
I will consider your suggestion and will see whether it can be implemented without any breaking changes. For this purpose, can you please send me a small dummy project with your exact architecture so I can test against. You can use Northwind or AdventureWorks for the sake of demonstration.
Thank in advance.
Ross
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
You can download from https://skydrive.live.com/redir.aspx?cid=b1465de519409505&resid=B1465DE519409505!139&parid=B1465DE519409505!137
remark 1.: the determination of real entitysetname is in refdEmployees_Loaded in MainWindow.xaml.cs, and replace the View property, and the binding to gridview and dataform created after it
remark 2: in DataForm Escape the newly created entity will not remove from datasoure (not in this app nor my business app)
remark 3: if I use auto generated fields, then the Cancel will throw some exception (MoveLast pehaps)
remark 4: I think You have to modify connection string in app.config (SQL Server name)
remark 5: the newly created object is a copy of another one, I do'nt know while, in my business application the new object is empty (always).
K2
It works - just some problem in Cancel, I do'nt while try set the properties of dropping object (and it is a non nullable string property).
K2
I will debug the code that you have sent me and see exactly what it does.
Meanwhile, I have a question for you. I've seen that you are acquainted with the source code, so suppose that I take this piece of code from the TryRefreshView method:
// ObjectQuery<Customer>
var propertyInfo =
this
.ObjectContext
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.FirstOrDefault(pi => pi.Name ==
this
.QueryName && IsValidObjectQueryProperty(pi));
if
(propertyInfo !=
null
)
{
// Customer
var entityType = propertyInfo.PropertyType.GetGenericArguments().First();
var objectQuery = propertyInfo.GetValue(
this
.ObjectContext,
null
);
// QueryableEntityCollectionView<Customer>
var genericQCVType =
typeof
(QueryableEntityCollectionView<>).MakeGenericType(
new
Type[] { entityType });
// new QueryableEntityCollectionView<Customer>(objectQuery, this.QueryName, this.RelatedObjects)
this
.View =
(QueryableCollectionView)Activator.CreateInstance(genericQCVType
, objectQuery
,
this
.QueryName
,
this
.RelatedObjects);
return
true
;
}
and I extract this to a new protected virtual method called CreateView or something like this, will you be able to derive from RadEntityFrameworkDataSource and override this method. In this way you will have the full and total freedom to create the view in any custom way that you want. And of course do the error handling appropriately.
In this way I will keep the control just as it is (i.e. no possible breaking changes for anyone else) and give you the ability ("with great power comes great responsibility") to "hack" the creating of the view.
What do you think? Will this be a viable solution for you case?
Regards,
Ross
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
While? Because I can derive not just RadEntityFrameworkDataSource and override CreateView, but it is possible to create QueryabelEntityCollectionView<T> derived view if needed.
So, your solution will be more general then my base problem reuires.
What do you think, when will be reachable the build including this modification?
K2
I have prepared an unofficial build with this change on my computer and updated the sample project that you sent me. Please give it a try and tell me whether it matches your requirements. I have derived from RadEntityFrameworkDataSource and called the derived class MyREFDS. Currently, I have copied the base implementation in the overloaded method which you can start tweaking around to see whether everything will be fine.
Here is how I changed the code:
private
bool
TryRefreshView()
{
if
(
this
.ObjectContext ==
null
||
string
.IsNullOrEmpty(
this
.QueryName))
{
return
false
;
}
if
(RadControl.IsInDesignMode)
{
this
.View =
new
QueryableCollectionView(Enumerable.Empty<
object
>());
return
true
;
}
var result =
this
.CreateView();
if
(result !=
null
)
{
this
.View = result;
return
true
;
}
return
false
;
}
/// <summary>
/// Creates the view.
/// </summary>
/// <returns>The view.</returns>
protected
virtual
QueryableCollectionView CreateView()
{
// ObjectQuery<Customer>
var propertyInfo =
this
.ObjectContext
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.FirstOrDefault(pi => pi.Name ==
this
.QueryName && IsValidObjectQueryProperty(pi));
if
(propertyInfo !=
null
)
{
// Customer
var entityType = propertyInfo.PropertyType.GetGenericArguments().First();
var objectQuery = propertyInfo.GetValue(
this
.ObjectContext,
null
);
// QueryableEntityCollectionView<Customer>
var genericQCVType =
typeof
(QueryableEntityCollectionView<>).MakeGenericType(
new
Type[] { entityType });
// new QueryableEntityCollectionView<Customer>(objectQuery, this.QueryName, this.RelatedObjects)
var result =
(QueryableCollectionView)Activator.CreateInstance(genericQCVType
, objectQuery
,
this
.QueryName
,
this
.RelatedObjects);
return
result;
}
throw
new
ArgumentException(
string
.Format(
"Cannot find a valid ObjectQuery named {0} on the ObjectContext."
,
this
.QueryName));
}
/// <summary>
/// Determines whether the property info is valid ObjectQuery.
/// </summary>
/// <param name="propertyInfo">The property info.</param>
/// <returns>
/// <c>true</c> if the property info is valid ObjectQuery; otherwise, <c>false</c>.
/// </returns>
public
static
bool
IsValidObjectQueryProperty(PropertyInfo propertyInfo)
{
return
propertyInfo.PropertyType.IsGenericType
&&
typeof
(ObjectQuery).IsAssignableFrom(propertyInfo.PropertyType)
&& propertyInfo.PropertyType.GetGenericArguments().Count() == 1
&&
typeof
(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType.GetGenericArguments().First());
}
And the overriden method that you can now do anything with:
public
class
MyREFDS : RadEntityFrameworkDataSource
{
protected
override
Telerik.Windows.Data.QueryableCollectionView CreateView()
{
// ObjectQuery<Customer>
var propertyInfo =
this
.ObjectContext
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.FirstOrDefault(pi => pi.Name ==
this
.QueryName && IsValidObjectQueryProperty(pi));
if
(propertyInfo !=
null
)
{
// Customer
var entityType = propertyInfo.PropertyType.GetGenericArguments().First();
var objectQuery = propertyInfo.GetValue(
this
.ObjectContext,
null
);
// QueryableEntityCollectionView<Customer>
var genericQCVType =
typeof
(QueryableEntityCollectionView<>).MakeGenericType(
new
Type[] { entityType });
// new QueryableEntityCollectionView<Customer>(objectQuery, this.QueryName, this.RelatedObjects)
var view =
(QueryableCollectionView)Activator.CreateInstance(genericQCVType
, objectQuery
,
this
.QueryName
,
this
.RelatedObjects);
return
view;
}
return
null
;
}
}
If it works fine for you, I will check in source control and hopefully on Monday you will get it "officially" with our next "Latest Internal Build". Please, test all corner cases that you might think of.
I am looking forward to hearing from you.
All the best,
Ross
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
Here it is my overridden CreateView method:
protected override Telerik.Windows.Data.QueryableCollectionView CreateView()
{
// ObjectQuery<Customer>
var propertyInfo = this.ObjectContext
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.FirstOrDefault(pi => pi.Name == this.QueryName && IsValidObjectQueryProperty(pi));
if (propertyInfo != null)
{
// Customer
var entityType = propertyInfo.PropertyType.GetGenericArguments().First();
var objectQuery = propertyInfo.GetValue(this.ObjectContext, null);
// QueryableEntityCollectionView<Customer>
var genericQCVType = typeof(QueryableEntityCollectionView<>).MakeGenericType(new Type[] { entityType });
string _queryName = this.QueryName;
//perhaps less is enough then EntityObject, I do'nt know
if (entityType.BaseType != typeof(EntityObject))
{
Type typeParent = entityType;
while (typeParent != null && typeParent.BaseType != typeof(EntityObject))
typeParent = typeParent.BaseType;
if (typeParent == null)
throw new Exception("ObjectQuery's generic argument is not EntityObject");
Type osetType = typeof(ObjectQuery<>).MakeGenericType(new Type[] { typeParent });
var esv = from PropertyInfo pi in ObjectContext.GetType().GetProperties()
where pi.PropertyType.IsSubclassOf(osetType)
select pi;
ObjectQuery oquery = esv.First().GetValue(ObjectContext, null) as ObjectQuery;
EntitySet es = oquery.GetType().GetProperty("EntitySet").GetValue(oquery, null) as EntitySet;
_queryName = es.Name;
}
// new QueryableEntityCollectionView<Customer>(objectQuery, this.QueryName, this.RelatedObjects)
var view =
(QueryableCollectionView)Activator.CreateInstance(genericQCVType
, objectQuery
, _queryName
, this.RelatedObjects);
return view;
}
return null;
}
K2
I have checked-in the source code and it will be available with our next Latest Internal Build.
I hope this will help you move forward with your project.
Ross
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
K2