ra0o0f / arangoclient.net

ArangoDB .NET Client with LINQ support
Apache License 2.0
98 stars 37 forks source link

Identifier properties in the base class a not recognized by the client #70

Open Hunter21007 opened 7 years ago

Hunter21007 commented 7 years ago

Hi,

i have a usecase where i define a class:

class MyBase
{
        [DocumentProperty(Identifier = IdentifierType.Handle)]
        public string Id { get; set; }
}

and derivate:

class MyDerivate: MyBase
{
      public string Name { get; set; }
}

if i use the Insert Method then the Id Property does not get filled by the client If i declare the id property in the derivate it works.

as i have found out you are using the GetAttribute by setting inherit to false this prevent the client from discovering the DocumentAttribute in the Base Class

typeSetting.TryAdd(m.Name, ReflectionUtils.GetAttribute<DocumentPropertyAttribute>(m, false));

My question is whether it is definitely required behavior or is it possible to change it in order to support inherited Identifier properties?

Thanks in advance

from public class DocumentPropertySetting : IDocumentPropertySetting:

        internal static IDocumentPropertySetting FindDocumentAttributeForType(Type type,string memberName)
        {
            ConcurrentDictionary<string, IDocumentPropertySetting> typeSetting = null;
            if (!cachedAttributeProperties.TryGetValue(type, out typeSetting))
            {
                var typeMemberInfos = ReflectionUtils.GetFieldsAndProperties_PublicInstance(type);

                typeSetting = new ConcurrentDictionary<string, IDocumentPropertySetting>();

                foreach (var m in typeMemberInfos)
                    typeSetting.TryAdd(m.Name, ReflectionUtils.GetAttribute<DocumentPropertyAttribute>(m, false));

                cachedAttributeProperties.TryAdd(type, typeSetting);
            }

            return typeSetting[memberName];
        }
ra0o0f commented 7 years ago

thanks @Hunter21007, i will release a fix asap.

tonys1110 commented 7 years ago

I have a class structure VERY similar to the original poster, and I'm having a problem with querying through derived classes. If query operations performed on a base-class IQueryable then the type is lost.

This produces the expected results (prints out some usernames from the database):

abstract class Query
{
    public abstract IQueryable<BaseDocument> CreateQuery(ArangoDatabase database);
}

class UserQ : Query
{
    public override IQueryable<BaseDocument> CreateQuery(ArangoDatabase database)
    {
        var query = database.Query<User>();

        return query.Where(u => AQL.Length(u.Name) == 4);
    }
}

class Program
{   
    static void RunQueryDisplayResults(ArangoDatabase database, Query query)
    {
        IQueryable<BaseDocument> results = query.CreateQuery(database);

        foreach (BaseDocument obj in results)
            Console.WriteLine(obj.ToString());
    }
}

But if I try to perform any additional query operations in the top-level RunQueryDisplayResults() function (OrderBy(), Skip(), Take(), etc) then I get a bunch of BaseDocument objects (not User or whatever concrete type was passed into the function).

class Program
{   
    static void RunQueryDisplayResults(ArangoDatabase database, Query query)
    {
        IQueryable<Base> results = query.Run(database).Skip(1).Take(2);

        foreach (Base obj in results)
            Console.WriteLine(obj.ToString());
    }
}

Produces the output below instead of printing 2 usernames:

ArangoConsoleTest.BaseDocument
ArangoConsoleTest.BaseDocument

I can do the OrderBy/Skip/Take/etc in the type-specific Query::CreateQuery and it will work. I can also cast the IQueryable<BaseDocument> a concrete type (like IQueryable<User>) in RunQueryDisplayResults() before doing Skip/Take and it will work. But both of these solutions aren't really doable when there are many document/query classes and defeat the use of inheritance in the first place.

ra0o0f commented 7 years ago

@tonys1110 sorry for the delay, i did not get what exactly you trying to say

1- BaseDocument.ToString() will print the class name, how query.Where(u => AQL.Length(u.Name) == 4) returns username? am i missing something in your code?

2- please end you query with a Select clause(always), and try again

3- can you provide a failing test, so i can test what you need to produce