【问题标题】:Unable to incorporate stored procedure results into Entity Framework Core无法将存储过程结果合并到 Entity Framework Core
【发布时间】:2020-09-08 03:00:15
【问题描述】:

我花了几个小时试图弄清楚如何将全文搜索合并到 Entity Framework Core 中。

我已经放弃尝试直接合并全文查询。于是我硬着头皮加了两个存储过程。

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql(@"CREATE PROCEDURE [dbo].[GetFullTextSearchResults]
    @SearchTerm     nvarchar(4000),
    @SkipRows       int,
    @TakeRows       int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT [Articles].[Id],
        [Articles].[Title],
        [Articles].[Slug],
        [Articles].[Description],
        [Categories].[Title] AS [Category],
        [Articles].[UserId],
        [AspNetUsers].[Name] AS [UserName],
        [Articles].[UtcDateModified]
    FROM [Articles]
    INNER JOIN CONTAINSTABLE([Articles], *, @SearchTerm) [t] ON [Articles].[Id] = [t].[Key]
    INNER JOIN [Subcategories] ON [Subcategories].[Id] = [Articles].[SubcategoryId]
    INNER JOIN [Categories] ON [Categories].[Id] = [Subcategories].[CategoryId]
    LEFT OUTER JOIN [AspNetUsers] ON [AspNetUsers].[Id] = [Articles].[UserId]
    WHERE [Articles].[Approved] = 1
    ORDER BY [t].[Rank] DESC
    OFFSET @SkipRows ROWS
    FETCH NEXT @TakeRows ROWS ONLY;
END");

    migrationBuilder.Sql(@"CREATE PROCEDURE [dbo].[GetFullTextSearchCount]
    @SearchTerm      nvarchar(4000)
AS
BEGIN
    SET NOCOUNT ON;
    SELECT COUNT(1)
    FROM [Articles]
    INNER JOIN CONTAINSTABLE([Articles], *, @SearchTerm) [t] ON [Articles].[Id] = [t].[Key]
    WHERE [Articles].[Approved] = 1
END");

但是,我似乎仍然无法合并它,因为返回的列与我的视图模型之一匹配,但与我的实体模型不匹配。我已经阅读了一个限制,即 Entity Framework Core 只能检索作为模型一部分的实体类型。 (我需要一些相关数据,下载整个实体模型会包含太多数据。)

我不知道为什么这会变得如此复杂。但在这一点上,如果我能做一个 ADO.NET 类型的查询,我会接受的。

那么,如何从GetFullTextSearchResults 检索结果?还有其他选择吗?

【问题讨论】:

标签: c# sql-server asp.net-core entity-framework-core full-text-search


【解决方案1】:

您可以创建与返回的列匹配的实体类型。

[NotMapped] 属性应用于实体类。在您的上下文中包含实体的DbSet。在 EF 配置中将其设置为无键,因此 EF 永远不会尝试更新它,也不会分配任何类型的表或视图名称。

modelBuilder.Entity<YourEntityName>().HasNoKey();

您可以使用以下方式检索数据:

var sessions = await _context.PersonSessionPaperRatingStatistics
    .FromSqlInterpolated($"EXECUTE YourStoredProcedureName {Parameter1},  {Parameter2}").ToListAsync().ConfigureAwait(true);

【讨论】:

    【解决方案2】:

    我为此奋斗了好几个小时。事实上,没有简单的方法可以在动态类中运行临时查询。

    所以我写了一个扩展方法来提供这个。代码只是访问DbConnect 并使用阅读器和反射来读取结果并填充目标类型。

    这种方法有一些限制。例如,它忽略任何事务。但是目标很简单,就是返回一些数据。

    public static async Task<IEnumerable<T>> SqlQuery<T>(this DbConnection connection, string query, params SqlParameter[] parameters) where T : new()
    {
        // TODO: Do we need to close in this case?
        if (connection.State != ConnectionState.Open)
            connection.Open();
    
        List<T> results = new List<T>();
    
        using (var cmd = connection.CreateCommand())
        {
            cmd.CommandText = query;
            cmd.CommandType = CommandType.Text;
            foreach (SqlParameter parameter in parameters)
                cmd.Parameters.Add(parameters);
    
            PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
    
            using var reader = await cmd.ExecuteReaderAsync();
    
            while (await reader.ReadAsync())
            {
                T item = Activator.CreateInstance<T>();
    
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    if (!await reader.IsDBNullAsync(i))
                    {
                        string name = reader.GetName(i);
                        PropertyInfo property = properties.FirstOrDefault(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
                        if (property != null && property.CanWrite)
                            property.SetValue(item, reader.GetValue(i));
                    }
                }
                results.Add(item);
            }
        }
        return results;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-05
      • 1970-01-01
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多