7

我有这样的现有功能

public int sFunc(string sCol , int iId)
{
    string sSqlQuery = "  select  " + sCol + " from TableName where ID = " +  iId ;
    // Executes query and returns value in column sCol
}

该表有四列存储整数值,我正在使用上述函数分别读取它们。

现在我将它转换为 Entity Framework 。

public int sFunc(string sCol , int iId)
{
     return Convert.ToInt32(TableRepository.Entities.Where(x => x.ID == iId).Select(x => sCol ).FirstOrDefault());
}

但是上面的函数返回错误

输入字符串格式不正确

因为它返回列名本身。

我不知道如何解决这个问题,因为我对 EF 很陌生。

任何帮助,将不胜感激

谢谢

4

6 回答 6

1

这可能有助于解决您的问题:

public int sFunc(string sCol, int iId)
{
    var _tableRepository = TableRepository.Entities.Where(x => x.ID == iId).Select(e => e).FirstOrDefault();
    if (_tableRepository == null) return 0;

    var _value = _tableRepository.GetType().GetProperties().Where(a => a.Name == sCol).Select(p => p.GetValue(_tableRepository, null)).FirstOrDefault();

    return _value != null ? Convert.ToInt32(_value.ToString()) : 0;
}

此方法现在适用于动态输入法参数sCol

于 2014-01-13T06:52:10.963 回答
0

您必须尝试使用​​动态 LINQ。详情在这里

于 2014-01-13T06:17:22.157 回答
0

8年后对OP没有用,但是这个问题有很多观点,所以我认为对其他人有一个正确的答案可能会有所帮助。

如果您使用实体框架,您应该进行 Linq 投影 ( Select()),因为这会导致在 db 端进行正确、高效的查询,而不是拉入整个实体。

但是,使用 Linq Select(),您通常必须提供 lambda,因此将您的列/属性名称放在字符串中是这里的主要困难。

最简单的解决方案是使用动态 LINQ(EntityFramework.DynamicLinq Nuget 包)。这个包提供了原始 Linq 方法的替代方案,这些方法将字符串作为参数,并将这些字符串转换为适当的表达式。

例子:

async Task<int> GetIntColumn(int entityId, string intColumnName)
{
    return await TableRepository.Entities
        .Where(x => x.Id == entityId)
        .Select(intColumnName) // Dynamic Linq projection
        .Cast<int>()
        .SingleAsync();
}

我也把它变成了一个async调用,因为这些天所有的数据库调用都应该异步执行。当你调用这个方法时,你必须得到await它的结果(即:)var res = await GetIntColumn(...);

通用变异

可能将其更改为扩展方法更有用IQueryable,并将列/属性类型转换为泛型类型参数,因此您可以将其与任何列/属性一起使用:

(前提是您的所有实体都有一个指定Id属性的通用接口。)

public static async Task<TColumn> GetColumn<TEntity, TColumn>(this IQueryable<TEntity> queryable, int entityId, string columnName)
    where TEntity : IEntity
{
    return await queryable
        .Where(x => x.Id == entityId)
        .Select(columnName) // Dynamic Linq projection
        .Cast<TColumn>()
        .SingleAsync();
}

这被称为:var result = await TableRepository.Entities.GetColumn<Entity, int>(id, columnName);

接受列列表的通用变体

您可以进一步扩展它以支持动态选择多个列:

public static async Task<dynamic> GetColumns<TEntity>(this IQueryable<TEntity> queryable, int entityId, params string[] columnNames)
    where TEntity : IEntity
{
    return await queryable
        .Where(x => x.Id == entityId)
        .Select($"new({string.Join(", ", columnNames)})")
        .Cast<dynamic>()
        .SingleAsync();
}

这被称为:var result = await TableRepository.Entities.GetColumns(id, columnName1, columnName2, ...);

由于返回类型及其成员在编译时是未知的,所以我们必须在dynamic这里返回。这使得处理结果变得困难,但如果你想要的只是序列化它并将其发送回客户端,那么就可以了。

于 2022-01-14T12:42:07.080 回答
-1

你可以这样做:

        var entity = _dbContext.Find(YourEntity, entityKey);
        // Finds column to select or update
        PropertyInfo propertyInfo = entity.GetType().GetProperty("TheColumnVariable");
于 2018-09-14T16:42:21.467 回答
-2

不要将字符串列名作为参数传递,而是尝试传递 lambda 表达式,例如:

sFunc(x => x.FirstColumnName, rowId);
sFunc(x => x.SecondColumnName, rowId);
...

这最终将为您提供列名的智能感知,因此当列名输入错误时,您可以避免可能出现的错误。

更多关于这里的信息:C# Pass Lambda Expression as Method Parameter

但是,如果你必须保持相同的方法签名,即支持其他/遗留代码,那么你可以试试这个:

public string sFunc(string sCol , int iId)
{
    return TableRepository.Entities.Where(x => x.ID == iId).Select(x => (string) x.GetType().GetProperty(sCol).GetValue(x)});
}

你可能需要稍微调整一下,我没有快速的测试方法。

于 2014-01-13T06:22:17.233 回答
-3

你可以使用反射,像这样(未经测试的代码):

public string sFunc(string sCol , int iId)
{
  var row = TableRepository.Entities.Where(x => x.ID == iId);
  var type = typeof(row);
  var propInfo = type.GetProperty(sCol);

  if (propInfo != null)
  {
    string value = (string)propInfo.GetValue(row);

    return value;
  }

  return null;
}
于 2014-01-13T06:28:09.150 回答