Select для структурных полей
От: Naf2000  
Дата: 05.03.21 07:49
Оценка:
Имею следующую таблицу:
    [Table(Schema = "dbo", Name = "Test")]
    [Column("Coord.X", MemberName = "Coord.X", CanBeNull = false)]
    [Column("Coord.Y", MemberName = "Coord.Y", CanBeNull = false)]
    [Column("Coord.Z.Z1", MemberName = "Coord.Z.Z1", CanBeNull = false)]
    [Column("Coord.Z.Z2", MemberName = "Coord.Z.Z2", CanBeNull = false)]
    public partial class Test
    {
        [Column, PrimaryKey, Identity] 
        public long ID;// { get; set; } 
        public Coord Coord;// { get; set; }
    }

Здесь Coord и Z struct-типы нескольких полей
Удалось научиться работать с ними в предикатах:
db.Tests.Where(t => t.Coord != default(Coord))

Однако, когда я пишу их в Selectничего не выходит:
db.Tests.Select(t => t.Coord).Distinct()

Исключение:

Вызвано исключение: "LinqToDB.Linq.LinqException" в linq2db.dll
Необработанное исключение типа "LinqToDB.Linq.LinqException" в linq2db.dll
Expression 't.Coord' is not a Field.

Что и где надо написать, чтобы linq2db понимал такие выражения?
Re: Select для структурных полей
От: Mace Windu  
Дата: 05.03.21 09:41
Оценка:
Здравствуйте, Naf2000, Вы писали:


N>Что и где надо написать, чтобы linq2db понимал такие выражения?


Я подозреваю написать(дописать в linq2db) придется довольно много чтобы такое заработало, Danchik поправит если не прав.

Создал feature request https://github.com/linq2db/linq2db/issues/2874
Re[2]: Select для структурных полей
От: Naf2000  
Дата: 05.03.21 11:09
Оценка:
Здравствуйте, Mace Windu, Вы писали:

MW>Здравствуйте, Naf2000, Вы писали:



N>>Что и где надо написать, чтобы linq2db понимал такие выражения?


MW>Я подозреваю написать(дописать в linq2db) придется довольно много чтобы такое заработало, Danchik поправит если не прав.


MW>Создал feature request https://github.com/linq2db/linq2db/issues/2874


Ну вот с условием не так сложно было сделать:
Expressions.MapBinary((Coord left, Coord right) => left == right, (Coord left, Coord right) => left.X == right.X && left.Y == right.Y && left.Z==right.Z);
Expressions.MapBinary((Coord left, Coord right) => left != right, (Coord left, Coord right) => !(left == right));
Expressions.MapMember((Coord left, Coord right) => left.Equals(right), (Coord left, Coord right) => (left == right));

db.Tests.Where(t => t.Coord != default(Coord))
Re: Select для структурных полей
От: Naf2000  
Дата: 10.03.21 11:18
Оценка:
Здравствуйте, Naf2000, Вы писали:

N>Что и где надо написать, чтобы linq2db понимал такие выражения?


Пока реализовал следующим образом:
namespace DataModels
{
    [AttributeUsage(AttributeTargets.Struct)]
    public class StructDBTypeAttribute : System.Attribute { }
    
    public static class Queryable
    {   
        
        public static IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
        {   
            var body = UnwrapExpression(selector.Body);
            var expression = (Expression<Func<TSource, TResult>>)Expression.Lambda(body, selector.Parameters);
            return System.Linq.Queryable.Select<TSource, TResult>(source, expression);
        }

        private static Expression UnwrapExpression(Expression expression)
        {
            switch (expression)
            {
                case NewExpression ex:
                    return Expression.New(ex.Constructor,
                                            ex.Arguments.Select(arg => UnwrapExpression(arg)),
                                            ex.Members);
                case MemberInitExpression ex:
                    return Expression.MemberInit(ex.NewExpression,
                                            ex.Bindings.Select(b => Expression.Bind(b.Member, UnwrapExpression(((MemberAssignment)b).Expression))));
                case MemberExpression ex:
                    var type = ex.Type;
                    if(type.GetCustomAttributes(typeof(StructDBTypeAttribute),false).Any())
                    {
                        var fields = type.GetFields();
                        var result =  Expression.MemberInit(Expression.New(type), fields.Select(f => Expression.Bind(f, Expression.MakeMemberAccess(ex, f))));
                        return UnwrapExpression(result);
                    }
                    else
                    {
                        return ex;
                    }
                default:
                    return expression;
            }
        }

    }
}


При этом сами структуры должны быть помечены атрибутом [StructDBType], а полям таблиц БД соответствуют поля структуры (на свойства думаю легко переделать для желающих, но есть момент с инициализацией вложенных структур).
Re[2]: Select для структурных полей
От: Danchik Украина  
Дата: 11.03.21 08:57
Оценка:
Здравствуйте, Naf2000, Вы писали:

N>Здравствуйте, Naf2000, Вы писали:


N>>Что и где надо написать, чтобы linq2db понимал такие выражения?


[Skip]

N>При этом сами структуры должны быть помечены атрибутом [StructDBType], а полям таблиц БД соответствуют поля структуры (на свойства думаю легко переделать для желающих, но есть момент с инициализацией вложенных структур).


Продумайте лучше API для задания такого поведения, а я уж закачу рукава да и сделаю.
Что-то типа этого OwnsOne
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.