使用LINQ to SQL搜索整个数据库

时间:2010-07-07 08:52:04

标签: c# .net vb.net linq linq-to-sql

LINQ to SQL是否可以搜索整个数据库(显然只有.dbml文件中映射的部分)才能匹配字符串?我正在尝试编写一个函数,它将采用一串“搜索术语”并搜索所有映射的实体并返回一个List(Of Object),它可以包含实体的混合,即如果我有一个表“Foo”和表“ Bar“并搜索”wibble“,如果”Foo“中有一行,而”Bar“中有一行包含”wibble“,我想返回一个包含”Foo“对象的List(Of Object)和一个”酒吧“对象。 这可能吗?

7 个答案:

答案 0 :(得分:8)

向你的老板询问以下内容:

“老板,当你去图书馆找一本关于小工具的书时,你是否走到第一个书架并开始阅读每本书以查看它是否相关,或者你是否使用某种预编译索引那个图书管理员已经提前为你配置了什么?“

如果他说“嗯,我会使用索引”,那么你需要一个全文索引。

如果他说“嗯,我会逐一阅读每本书”,那么你需要一份新工作,一位新老板,或两者兼而有之: - )

答案 1 :(得分:7)

LINQ to SQL,一般来说,ORM甚至SQL都是这种查询的不匹配。您正在描述全文搜索,因此您应该使用SQL Server的全文搜索功能。自2000年以来,所有版本和版本都提供Full Text Search,包括SQL Server Express。您需要创建一个FTS目录并编写在查询中使用CONTAINS,FREETEXT函数的查询。

为什么需要这样的功能?除非您特别想要为您的应用程序启用FTS,否则这是一种......奇怪的...访问您的数据的方式。

答案 2 :(得分:3)

这可能是“可能的”,但大多数数据库都是通过网络或网络访问的,因此这是一项非常昂贵的操作。所以这听起来很糟糕。

还有表名和列名的问题,这可能是你最大的问题。可以通过反射获取列名,但我不知道表名:

foreach (PropertyInfo property in typeof(TEntity).GetProperties())
   yield return property.Name;
编辑:@Ben,你说错了。

答案 3 :(得分:2)

这可以做但不会很漂亮。有几种可能的解决方案。

1。自己编写每个表的查询,并在查询方法中执行所有查询。

var users = context.Users
    .Where(x => x.FirstName.Contains(txt) || x.LastName.Contains(txt))
    .ToList();

var products = context.Products
    .Where(x => x.ProductName.Contains(txt));

var result = user.Cast<Object>().Concat(products.Cast<Object>());

2. 将所有(相关)表提取到内存中并使用反射执行搜索。编写的代码越少,就会产生巨大的性能影响。

3. 使用反射为搜索构建表达式树。这可能是最好的解决方案,但实现起来可能具有挑战性。

4. 使用专为全文搜索设计的内容 - 例如集成到SQL Server或Apache Lucene中的全文搜索。

所有LINQ解决方案(可能)每个表需要一个查询,如果您有许多表,则会产生不可忽视的性能影响。在这里,人们应该寻找一种解决方案,将这些查询批量分成一个。我们使用LINQ to SQL的一个项目使用了一个库进行批处理查询,但我不知道它的名称是什么以及它究竟能做什么,因为我大部分时间都在前端团队工作。

答案 4 :(得分:0)

可能,但从我的观点来看,不建议这样做。考虑拥有100个表的1000K记录。 性能低下您可以通过在数据库级别创建Sp并通过实体调用来实现 Linq to SQL 。它会比你试图达到的速度快得多=)

答案 5 :(得分:0)

迟到的回答,但由于我不得不为自己想出一些东西,这里就是这样。我写了以下内容来搜索所有表的所有列以进行字符串匹配。这与数据取证任务有关,该任务是在重量大约为24GB的数据库中查找字符串匹配的所有出现的。在这个大小,你可以想象使用游标或单线程查询会相当慢,搜索整个数据库需要很长时间。我编写了以下CLR存储过程来为我的服务器端工作并以XML格式返回结果,同时强制并行化。它的速度非常快。标准AdventureWorks2017数据库的数据库范围搜索在不到2秒的时间内完成。享受!

  

示例用法:

     

使用服务器上的所有可用处理器:

EXEC [dbo].[SearchAllTables] @valueSearchTerm = 'john michael'
     

将服务器限制为4个并发线程:

EXEC [dbo].[SearchAllTables] @valueSearchTerm = 'john michael', @maxDegreeOfParallelism = 4
     

在搜索字词中使用逻辑运算符:

EXEC [dbo].[SearchAllTables] @valueSearchTerm = '(john or michael) and not jack', @tablesSearchTerm = 'not contact'
     

将搜索限制为包含某些搜索字词的表名和/或列名:

EXEC [dbo].[SearchAllTables] @valueSearchTerm = 'john michael', @tablesSearchTerm = 'person contact', @columnsSearchTerm = 'address name'
     

将搜索结果限制在找到术语的每个表的第一行:

EXEC [dbo].[SearchAllTables] @valueSearchTerm = 'john michael', @getOnlyFirstRowPerTable = 1
     

仅将搜索限制为模式只会自动返回每个表的第一行:

EXEC [dbo].[SearchAllTables] @tablesSearchTerm = 'person contact'
     

仅返回搜索查询:

EXEC [dbo].[SearchAllTables] @valueSearchTerm = 'john michael', @tablesSearchTerm = 'person contact', @onlyOutputQueries = 1
     

将结果捕获到临时表和排序中:

CREATE TABLE #temp (Result NVARCHAR(MAX));
INSERT INTO #temp
    EXEC [dbo].[SearchAllTables] @valueSearchTerm = 'john';
SELECT * FROM #temp ORDER BY Result ASC;
DROP TABLE #temp;

https://pastebin.com/RRTrt8ZN

答案 6 :(得分:0)

我最终写了这个小的自定义宝石(给了搜索词找到所有匹配的记录):

namespace SqlServerMetaSearchScan
{
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading;
    using System.Xml;

public class Program
{
    #region Ignition
    public static void Main(string[] args)
    {
        // Defaulting
        SqlConnection connection = null;

        try
        {               
            // Questions
            ColorConsole.Print("SQL Connection String> ");
            string connectionString = Console.ReadLine();
            ColorConsole.Print("Search Term (Case Ignored)> ");
            string searchTerm = Console.ReadLine();
            ColorConsole.Print("Skip Databases (Comma Delimited)> ");
            List<string> skipDatabases = Console.ReadLine().Split(',').Where(item => item.Trim() != string.Empty).ToList();

            // Search
            connection = new SqlConnection(connectionString);
            connection.Open();

            // Each database
            List<string> databases = new List<string>();
            string databasesLookup = "SELECT name FROM master.dbo.sysdatabases";
            SqlDataReader reader = new SqlCommand(databasesLookup, connection).ExecuteReader();
            while (reader.Read())
            {
                // Capture
                databases.Add(reader.GetValue(0).ToString());
            }

            // Build quintessential folder
            string logsDirectory = @"E:\Logs";
            if (!Directory.Exists(logsDirectory))
            {
                // Build
                Directory.CreateDirectory(logsDirectory);
            }
            string baseFolder = @"E:\Logs\SqlMetaProbeResults";
            if (!Directory.Exists(baseFolder))
            {
                // Build
                Directory.CreateDirectory(baseFolder);
            }

            // Close reader
            reader.Close();                

            // Sort databases
            databases.Sort();

            // New space
            Console.WriteLine(Environment.NewLine + " Found " + databases.Count + " Database(s) to Scan" + Environment.NewLine);

            // Deep scan
            foreach (string databaseName in databases)
            {
                // Skip skip databases
                if (skipDatabases.Contains(databaseName))
                {
                    // Skip 
                    continue;
                }

                // Select the database
                new SqlCommand("USE " + databaseName, connection).ExecuteNonQuery();

                // Table count
                int tablePosition = 1;

                try
                {
                    // Defaulting
                    List<string> tableNames = new List<string>();

                    // Schema examination
                    DataTable table = connection.GetSchema("Tables");

                    // Query tables
                    string tablesLookup = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES";
                    using (SqlDataReader databaseReader = new SqlCommand(tablesLookup, connection).ExecuteReader())
                    {
                        // Get data
                        while (databaseReader.Read())
                        {
                            // Push
                            if (databaseReader.GetValue(0).ToString().Trim() != string.Empty)
                            {
                                tableNames.Add(databaseReader.GetValue(0).ToString());
                            }
                        }

                        // Bail
                        databaseReader.Close();
                    }

                    // Sort
                    tableNames.Sort();                        

                    // Cycle tables
                    foreach (string tableName in tableNames)
                    {
                        // Build data housing
                        string databasePathName = @"E:\Logs\\SqlMetaProbeResults" + databaseName;
                        string tableDirectoryPath = @"E:\Logs\SqlMetaProbeResults\" + databaseName + @"\" + tableName;

                        // Count first
                        int totalEntityCount = 0;
                        int currentEntityPosition = 0;                            
                        string countQuery = "SELECT count(*) FROM " + databaseName + ".dbo." + tableName;
                        using (SqlDataReader entityCountReader = new SqlCommand(countQuery, connection).ExecuteReader())
                        {
                            // Query count
                            while (entityCountReader.Read())
                            {
                                // Capture
                                totalEntityCount = int.Parse(entityCountReader.GetValue(0).ToString());
                            }

                            // Close
                            entityCountReader.Close();
                        }

                        // Write the objects into the houseing
                        string jsonLookupQuery = "SELECT * FROM " + databaseName + ".dbo." + tableName;
                        using (SqlDataReader tableReader = new SqlCommand(jsonLookupQuery, connection).ExecuteReader())
                        {                                                
                            // Defaulting
                            List<string> fieldValueListing = new List<string>();

                            // Read continue
                            while (tableReader.Read())
                            {                                   
                                // Increment
                                currentEntityPosition++;

                                // Defaulting
                                string identity = null;

                                // Gather data
                                for (int i = 0; i < tableReader.FieldCount; i++)
                                {
                                    // Set
                                    if (tableReader.GetName(i).ToUpper() == "ID")
                                    {
                                        identity = tableReader.GetValue(0).ToString();
                                    }
                                    else
                                    {
                                        // Build column data entry
                                        string thisColumn = tableReader.GetValue(i) != null ? "'" + tableReader.GetValue(i).ToString().Trim() + "'" : string.Empty;

                                        // Piece
                                        fieldValueListing.Add(thisColumn);
                                    }
                                }

                                // Path-centric
                                string explicitIdentity = identity ?? Guid.NewGuid().ToString().Replace("-", string.Empty).ToLower();
                                string filePath = tableDirectoryPath + @"\" + "Obj." + explicitIdentity + ".json";
                                string reStringed = JsonConvert.SerializeObject(fieldValueListing, Newtonsoft.Json.Formatting.Indented);
                                string percentageMark = ((double)tablePosition / (double)tableNames.Count * 100).ToString("#00.0") + "%";                                                      
                                string thisMarker = Guid.NewGuid().ToString().Replace("-", string.Empty).ToLower();
                                string entityPercentMark = string.Empty;
                                if (totalEntityCount != 0 && currentEntityPosition != 0)
                                {
                                    // Percent mark
                                    entityPercentMark = ((double)currentEntityPosition / (double)totalEntityCount * 100).ToString("#00.0") + "%";
                                }

                                // Search term verify
                                if (searchTerm.Trim() != string.Empty)
                                {
                                    // Search term scenario
                                    if (reStringed.ToLower().Trim().Contains(searchTerm.ToLower().Trim()))
                                    {
                                        // Lazy build
                                        if (!Directory.Exists(tableDirectoryPath))
                                        {
                                            // Build
                                            Directory.CreateDirectory(tableDirectoryPath);
                                        }

                                        // Has the term
                                        string idMolding = identity == null || identity == string.Empty ? "No Identity" : identity;
                                        File.WriteAllText(filePath, reStringed);
                                        ColorConsole.Print(percentageMark + " => " + databaseName + "." + tableName + "." + idMolding + "." + thisMarker + " (" + entityPercentMark + ")", ConsoleColor.Green, ConsoleColor.Black, true);
                                    }
                                    else
                                    {
                                        // Show progress                                            
                                        string idMolding = identity == null || identity == string.Empty ? "No Identity" : identity;
                                        ColorConsole.Print(percentageMark + " => " + databaseName + "." + tableName + "." + idMolding + "." + thisMarker + " (" + entityPercentMark + ")", ConsoleColor.Yellow, ConsoleColor.Black, true);
                                    }
                                }
                            }

                            // Close
                            tableReader.Close();
                        }

                        // Increment
                        tablePosition++;
                    }                        
                }
                catch (Exception err)
                {
                    ColorConsole.Print("DB.Tables!: " + err.Message, ConsoleColor.Red, ConsoleColor.White, false);                        
                }
            }
        }
        catch (Exception err)
        {
            ColorConsole.Print("KABOOM!: " + err.ToString(), ConsoleColor.Red, ConsoleColor.White, false);                
        }
        finally
        {
            try { connection.Close(); }
            catch { }
        }


        // Await
        ColorConsole.Print("Done.");
        Console.ReadLine();
    }
    #endregion

    #region Cores
    public static string GenerateHash(string inputString)
    {
        // Defaulting
        string calculatedChecksum = null;

        // Calculate
        SHA256Managed checksumBuilder = new SHA256Managed();
        string hashString = string.Empty;
        byte[] hashBytes = checksumBuilder.ComputeHash(Encoding.ASCII.GetBytes(inputString));
        foreach (byte theByte in hashBytes)
        {
            hashString += theByte.ToString("x2");
        }
        calculatedChecksum = hashString;

        // Return
        return calculatedChecksum;
    }
    #endregion


    #region Colors
    public class ColorConsole
    {
        #region Defaulting
        public static ConsoleColor DefaultBackground = ConsoleColor.DarkBlue;
        public static ConsoleColor DefaultForeground = ConsoleColor.Yellow;
        public static string DefaultBackPorch = "                                                                              ";
        #endregion

        #region Printer Cores
        public static void Print(string phrase)
        {
            // Use primary
            Print(phrase, DefaultForeground, DefaultBackground, false);
        }
        public static void Print(string phrase, ConsoleColor customForecolor)
        {
            // Use primary
            Print(phrase, customForecolor, DefaultBackground, false);
        }
        public static void Print(string phrase, ConsoleColor customBackcolor, bool inPlace)
        {
            // Use primary
            Print(phrase, DefaultForeground, customBackcolor, inPlace);
        }
        public static void Print(string phrase, ConsoleColor customForecolor, ConsoleColor customBackcolor)
        {
            // Use primary
            Print(phrase, customForecolor, customBackcolor, false);
        }
        public static void Print(string phrase, ConsoleColor customForecolor, ConsoleColor customBackcolor, bool inPlace)
        {
            // Capture settings
            ConsoleColor captureForeground = Console.ForegroundColor;
            ConsoleColor captureBackground = Console.BackgroundColor;

            // Change colors
            Console.ForegroundColor = customForecolor;
            Console.BackgroundColor = customBackcolor;

            // Write
            if (inPlace)
            {
                // From beginning of this line + padding
                Console.Write("\r" + phrase + DefaultBackPorch);
            }
            else
            {
                // Normal write
                Console.Write(phrase);
            }

            // Revert
            Console.ForegroundColor = captureForeground;
            Console.BackgroundColor = captureBackground;
        }
        #endregion
    }
    #endregion
}
}