The documentation Mixing CLR Types and Artificial Properties describes how to create mixing types.
But when I extend type with artificial properties new derived class isn't created. And I cannot select or filter artificial properties using Dynamic LINQ. It throws the following error: No property or field 'TestField' exists in type 'TestClass'
How can I query (filter/selecting) mixing types?
15 Answers, 1 is accepted
Can you please share with us the code you are using to extend the model?
Basically extending the model with artificial types will generated them directly into an assembly. You will not actually see them in your solution as generated code. After this is done you should be able to query them successfully with dynamic linq. Can you please make sure that you are using the same names when querying? You can try to query with both field names and property names.
Petar
Telerik

MetdataSource:
public
class
FluentModelMetadataSource : FluentMetadataSource
{
protected
override
IList<MappingConfiguration> PrepareMapping()
{
List<MappingConfiguration> configurations =
new
List<MappingConfiguration>();
MappingConfiguration<Person> personConfiguraiton =
new
MappingConfiguration<Person>();
personConfiguraiton.MapType(p =>
new
{
PersonId = p.Id,
LastName = p.LastName,
FirstName = p.FirstName,
Contact = p.Address
}).ToTable(
"People"
);
personConfiguraiton.HasProperty(p => p.Id).IsIdentity(KeyGenerator.Autoinc);
personConfiguraiton.HasArtificialPrimitiveProperty<
int
>(
"Age"
);
personConfiguraiton.HasArtificialProperty<
byte
[]>(
"Picture"
);
configurations.Add(personConfiguraiton);
return
configurations;
}
protected
override
void
SetContainerSettings(MetadataContainer container)
{
MetaNameGenerator nameGenerator = container.NameGenerator;
nameGenerator.RemoveCamelCase =
false
;
nameGenerator.SourceStrategy = NamingSourceStrategy.AutomaticProperty;
nameGenerator.ResolveReservedWords =
false
;
container.DefaultMapping.NullForeignKey =
true
;
}
}
public
class
Person
{
public
int
Id {
get
;
set
; }
public
string
FirstName {
get
;
set
; }
public
string
LastName {
get
;
set
; }
public
string
Address {
get
;
set
; }
}
using
(var ctx =
new
FluentModel(
"MixingTestConn"
))
{
var persons = ctx.GetAll<Person>();
var queryByfirstName = persons.Where(
"FirstName = \"Olga\""
);
var queryBytAge = persons.Where(
"Age > 20"
);
//Error: No property or field 'Age' exists in type 'Person'
var queryBytAge = persons.Where(
"age > 20"
);
//Error: No property or field 'age' exists in type 'Person'
}
Also
ctx.GetAll<Person>()
doesn't return properties Age and Picture which created by artificial Api.Thanks.
You said you are extending an already existing persistent type in your model? If I understood you correctly you should be merging this fluent generated model with your real model (probably an rlinq file). Is that the case? Or are you just trying to extend a normal persistent type with a few artificial properties?
Regards,Petar
Telerik

I have the same problem. I have normal persistent type and want to add some artificial field.
If I add it with artificial api I cannot query it and make filters using this property.
Dynamic LINQ simply throws the following exception: "ExceptionMessage: "No property or field 'EmployeeCode' exists in type 'User'".
Because new derived class is not created for this persistent type and it doesn't have artificial field named EmployeeCode.
I will have to ask you the same. Can you please include the code you are using for extending the model? Are you merging your old model with your new model? If so, how?
Any information you can share on this subject will be of great help as so far we are unable to reproduce this false behavior.
Petar
Telerik

I attached tiny project that reproduces the problem.
Thank you for assistance!
Link: https://disk.yandex.com/public/?hash=aSRqf11BLw9eNTGL4AZTLSAvYplcnRFkg6wWTA5SRx4%3D&locale=en
Best Regards,
Andrey
The problem here is that when we are extending an already present type we cannot really add a field to the already compiled assembly. The way the artificial works is that we create a temp assembly where the type does have the field. However in your case the type is loaded from the original assembly where the field is indeed not present. What you can do to fix this is to slightly rewrite your query like this:
var users = ctx.GetAll<User>().Where(x => x.FieldValue<
int
>(
"Age"
) > 10);
Petar
Telerik

But how can I get the same with Dynamic LINQ?

var users = ctx.GetAll(
"MixingTypesTest.User"
).Where(
"val_int(Age) > 10"
).Select(
"new (val(Age) as w)"
).OfType<
object
>().ToArray();
If this may seem interesting to someone modified Dynamic.cs available here: http://yadi.sk/d/vrQxLwZi8TaWS
Format of call: val(XXX) or val_TYPE(XXX)
For example: val_long(Age), val_int(Height), val(Age)
If type name is not specified then object is implied.
That is a good solution should you want to use the dynamic linq way. We still advice you to stick to our API in the cases that you can but if your scenario does not allow that then your solution should work out just fine.
Regards,Petar
Telerik

I have static type (enhanced and mapped) to which I add in runtime artificial association property to some artificial class. To construct query for this association field I have to use dynamic constructed expression with ExtensionMethods.FieldValue<T> method. But when T is artificial type the following exception occurs:
ExceptionMessage: "Specified method is not supported.",
ExceptionType: "System.NotSupportedException",
StackTrace: " at System.Reflection.Emit.MethodBuilderInstantiation.GetParameters()
at System.Dynamic.Utils.TypeExtensions.GetParametersCached(MethodBase method)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
It occurs due to runtime creation of generic method with artificial type T. But .NET have limitations in implementation of this feature.
Can you please add non-generic version of FieldValue method that takes type as second argument? Or are there any other solutions?
Can you provide us with the code of the mapping and the value extraction that is causing the exception?
You can attach either a complete project or just the code snippets for the normal type and artificial type mappings and the query that attempts to read the values from the database.
Based on the description that you have posted I suppose that you have a navigation property between two artificial types. Am I correct?
Regards,
Viktor Zhivkov
Telerik

Trying to explain more clearly:
1. I have a normal type (User)
2. I create an artificial type (Department). Department is artificial runtime type
3. I create navigation artificial property from normal type to artificial type (User.DepartmentFk -> Department)
4. When I am trying to get property from artificial type I am getting an error (User.FieldValue<Department>("DepartmentFk").Title).
Department is artificial type and I cannot access it in static way. I have to construct ExpressionTree in runtime to create correct LINQ query.
But when I do this, the exception occurs. The code snippet:
var method =
typeof
(ExtensionMethods).GetMethod(
"FieldValue"
).MakeGenericMethod(artificialDepartmentType);
return
Expression.Call(
null
, method,
new
[] { instance, Expression.Constant("DepartmentFk") });
If you do not understand or do not reproduce the problem I will try to create small solution.
Thanks for the detailed information.
I believe that you can accomplish the same result using a lot simpler code by using FieldValue<object> rather than building a new generic method with the correct artificial type.
I have prepared a small demo application that reproduces the scenario that I believe you have described. You can find it attached. In the sample I am using the latest version of OpenAccess, but the required API is available already in the version you may be using (2013.2.702 if I am correct).
If you think I have misinterpreted your scenario, please let us know so we can alter the approach to suit better your needs.
Regards,
Viktor Zhivkov
Telerik

Thank you very much. It is great and working idea!
OpenAccess - very cool thing too. Thank you again.