This is a migrated thread and some comments may be shown as answers.

Using Dynamic Linq with mixing types

15 Answers 735 Views
Development (API, general questions)
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Dmitry
Top achievements
Rank 1
Dmitry asked on 01 Aug 2013, 07:43 AM
Hi.

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

Sort by
0
PetarP
Telerik team
answered on 05 Aug 2013, 02:31 PM
Hello Dmitry,

 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.

Regards,
Petar
Telerik
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
0
Dmitry
Top achievements
Rank 1
answered on 06 Aug 2013, 08:09 AM
As you requested.
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;
    }
}
Person:
public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
}
Using:
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.
0
PetarP
Telerik team
answered on 09 Aug 2013, 07:59 AM
Hello Dmitry,

 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
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
0
Andrey
Top achievements
Rank 1
answered on 20 Aug 2013, 07:17 AM
Hello!

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. 

Andrey
0
PetarP
Telerik team
answered on 22 Aug 2013, 03:02 PM
Hi Andrew,

 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.

Regards,
Petar
Telerik
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
0
Andrey
Top achievements
Rank 1
answered on 23 Aug 2013, 08:20 AM
Hello!

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
0
PetarP
Telerik team
answered on 28 Aug 2013, 08:29 AM
Hi,

 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);
This way using our extension method FIeldValue you can be sure that you are getting the correct value.

Regards,
Petar
Telerik
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
0
Andrey
Top achievements
Rank 1
answered on 28 Aug 2013, 08:43 AM
Oh, Petar, thanks! That's great!

But how can I get the same with Dynamic LINQ? 
0
Andrey
Top achievements
Rank 1
answered on 29 Aug 2013, 04:28 PM
Figured out about DynamicLINQ and modified some LINQ-library code. Now I can do that this way:
var users = ctx.GetAll("MixingTypesTest.User").Where("val_int(Age) > 10").Select("new (val(Age) as w)").OfType<object>().ToArray();
And it does work.

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.


0
PetarP
Telerik team
answered on 02 Sep 2013, 08:19 AM
Hello Andrew,

 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
OpenAccess ORM Q2 2013 brings you a more powerful code generation and a unique Bulk Operations support with LINQ syntax. Check out the list of new functionality and improvements shipped with this release.
0
Andrey
Top achievements
Rank 1
answered on 17 Dec 2013, 01:09 PM
Hello!

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?
0
Viktor Zhivkov
Telerik team
answered on 18 Dec 2013, 12:12 PM
Hello Andrew,

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
OpenAccess ORM Q3 2013 simplifies your model operations even further providing you with greater flexibility. Check out the list of new features shipped with our latest release!
0
Andrey
Top achievements
Rank 1
answered on 18 Dec 2013, 03:32 PM
Hello, Viktor!

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.
0
Viktor Zhivkov
Telerik team
answered on 20 Dec 2013, 01:59 PM
Hello Andrew,

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
OpenAccess ORM Q3 2013 simplifies your model operations even further providing you with greater flexibility. Check out the list of new features shipped with our latest release!
0
Andrey
Top achievements
Rank 1
answered on 21 Dec 2013, 08:43 AM
Viktor,

Thank you very much. It is great and working idea!

OpenAccess - very cool thing too. Thank you again.
Tags
Development (API, general questions)
Asked by
Dmitry
Top achievements
Rank 1
Answers by
PetarP
Telerik team
Dmitry
Top achievements
Rank 1
Andrey
Top achievements
Rank 1
Viktor Zhivkov
Telerik team
Share this question
or