Создать расширение IQueryable <T>, используя базовый класс в EF - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь создать многократно используемые поисковые запросы в моем базовом классе, поэтому мне не нужно повторять один и тот же код для каждого класса с производными данными, но я не могу заставить инфраструктуру сущностей играть хорошо.

У меня есть 3классы: CMEntityBase CMSite CMSiteServer

Site & SiteServer оба являются производными от CMEntityBase, который имеет общие свойства (ID, имя и т. д.)

Я хочу определить некоторые общие запросы: например, GetByName

using (var db = new LNOSCMDataModel())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var servers = db.CMSiteServers.
                    AsNoTracking().
                    GetByName(id,Active).
                    ConvertToAPIVM().ToList();
}

я попытался определить GetByName несколькими способами:

базовый класс:

    public static IQueryable<CMEntityBase> GetByName(this IQueryable<CMEntityBase> Entities, string Name, bool Active = true)
    {
        return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false);//.Cast<IEntity>();
    }

универсальный:

public static IQueryable<T> GetByName<T>(this IQueryable<CMEntityBase> Entities, string Name, bool Active = true) where T : CMEntityBase
        {
            return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false).Cast<T>();
        }

я попытался определить базовый классв качестве интерфейса и в общем случае с использованием T: class, IEntity (interface) -> этот подход возник из: LINQ to Entities поддерживает только приведение типов примитивов или перечислений EDM с интерфейсом IEntity

в конечном итоге все они возвращают ошибку:

LINQ to Entities поддерживает только приведение типов примитивов или перечислений EDM с интерфейсом IEntity.

в конечном счете, я хочуo определить запрос по свойствам базового класса, но вывести дочерний класс.сейчас кажется, что мне нужно скопировать / вставить мои методы для производного класса.

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Вместо того, чтобы принять IQueryable типа, отличного от того, который вы хотите, и попытаться привести его (что, как указывает ошибка, не поддерживается), вам просто нужно принять IQueryable фактического типа, которыйВаш запрос уже есть, так что нет необходимости приводить его.В этом случае это так же просто, как использование универсального типа в исходном запросе, а не базового типа:

public static IQueryable<T> GetByName<T>(this IQueryable<T> Entities, string Name, bool Active = true)
    where T : CMEntityBase //or the interface that specifies the needed members
{
    return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false);
}
0 голосов
/ 11 декабря 2018

После долгих экспериментов было решено создать базовый класс как абстрактный

public abstract class CMEntityBase
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public abstract decimal ID { get; set; }


    [StringLength(50)]
    public abstract string Name { get; set; }

    ....
}

определить мое расширение в статическом классе расширений, ключом здесь является использование .Select (e=> e как T), чтобы преобразовать его обратно в дочерний класс .

public static partial class CMEntityBaseExtensions
{
    public static IQueryable<T> GetByName<T>(this IQueryable<T> Entities, string Name, bool Active = true) where T : CMEntityBase
    {
        return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false).
                 Select(e => e as T); // cast back to child!
    }
}

, тогда я могу использовать его в моем контроллере:

 var servers1 = db.CMSiteServers
                .AsNoTracking().
                GetByName(id, Active);

и событие использовать my 'Casting 'функция для преобразования в модель представления

            var servers = servers1.
                ConvertToAPIVM().ToList();

, которая выглядит следующим образом:

public static partial class CMSiteServerExtensions
{
    public static IQueryable<CMSiteServerAPIVM> ConvertToAPIVM(this IQueryable<CMSiteServer> Servers)
    {
        return Servers.Select(ss => new CMSiteServerAPIVM()
        {
            SiteServerID = ss.ID,
            Name = ss.Name,
            Description = ss.Description,
            ...
        }
    }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...