C# LINQ к SQL: Рефакторинг этого Универсального метода GetByID

Это можно сделать с помощью filter_at, указав интересующие столбцы

library(dplyr)
df1 %>% 
   filter_at(vars(col1, col2), all_vars(. != 0))

данные

df1 <- data.frame(col1 = c(0, 1, 2, 3), col2 = c(1, 0, 2, 4), col3 = c(1, 1, 0, 0))
21
задан Community 23 May 2017 в 12:34
поделиться

5 ответов

Вам нужно построить дерево выражений, которое может понять LINQ to SQL . Предполагая, что ваше свойство "id" всегда называется "id":

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                "id"
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}

Это должно сработать. Он был бесстыдно заимствован из этого блога . Это в основном то, что делает LINQ to SQL, когда вы пишете запрос, подобный

var Q = from t in Context.GetTable<T)()
        where t.id == id
        select t;

. Вы просто выполняете работу для LTS, потому что компилятор не может создать это для вас, поскольку ничто не может навязать то, что у T есть свойство "id", и вы не можете отобразить произвольное свойство "id" из интерфейса с базой данных.

==== UPDATE ====

Хорошо, вот простая реализация для поиска имени первичного ключа, при условии, что есть только один (не составной) первичный ключ) и при условии, что все хорошо по типу (т. е. ваш первичный ключ совместим с «коротким» типом, который вы используете в функции GetById):

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                GetPrimaryKeyName<T>()
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}


public string GetPrimaryKeyName<T>()
{
    var type = Mapping.GetMetaType(typeof(T));

    var PK = (from m in type.DataMembers
              where m.IsPrimaryKey
              select m).Single();
    return PK.Name;
}
18
ответ дан 29 November 2019 в 21:54
поделиться

Что, если вы переделаете это для использования GetTable (). Where (...) и поместите туда свою фильтрацию?

Это было бы более эффективно, поскольку метод расширения Where должен принимать заботиться о вашей фильтрации лучше, чем извлекать всю таблицу из списка.

1
ответ дан 29 November 2019 в 21:54
поделиться

Some thoughts...

Just remove the ToList() call, SingleOrDefault works with an IEnumerably which I presume table is.

Cache the call to e.GetType().GetProperties().First() to get the PropertyInfo returned.

Cant you just add a constraint to T that would force them to implement an interface that exposes the Id property?

1
ответ дан 29 November 2019 в 21:54
поделиться

Относительно:

System.NotSupportedException: член 'MusicRepo_DataContext.IHasID.ID' не имеет поддерживаемого перевода в SQL

Простой обходной путь к вашей первоначальной проблеме - указать выражение. Смотрите ниже, это работает для меня как прелесть.

public interface IHasID
{
    int ID { get; set; }
}
DataContext [View Code]:

namespace MusicRepo_DataContext
{
    partial class Artist : IHasID
    {
        [Column(Name = "ArtistID", Expression = "ArtistID")]
        public int ID
        {
            get { return ArtistID; }
            set { throw new System.NotImplementedException(); }
        }
    }
}
0
ответ дан 29 November 2019 в 21:54
поделиться

Возможно, выполнение запроса может быть хорошей идеей.

public static T GetByID(int id)
    {
        Type type = typeof(T);
        //get table name
        var att = type.GetCustomAttributes(typeof(TableAttribute), false).FirstOrDefault();
        string tablename = att == null ? "" : ((TableAttribute)att).Name;
        //make a query
        if (string.IsNullOrEmpty(tablename))
            return null;
        else
        {
            string query = string.Format("Select * from {0} where {1} = {2}", new object[] { tablename, "ID", id });

            //and execute
            return dbcontext.ExecuteQuery<T>(query).FirstOrDefault();
        }
    }
0
ответ дан 29 November 2019 в 21:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: