1

文字列変数を介して実行時に選択されたテーブルで LINQ を実行する方法を探しています。

これは私がこれまでにリフレクションを使用したものです:

private Entities ctx = new Entities();

public List<AtsPlatform> GetAtsPlatformByName(string atsPlatformName)
{

    List<AtsPlatform> atsPlatform = null;
    System.Reflection.PropertyInfo propertyInfo = ctx.GetType().GetProperty(atsPlatformName.ToLower());
    var platform = propertyInfo.GetValue(ctx, null);

    // it fails here highlighting "platform" with error that reads "Error   1   Could not find an implementation of the query pattern for source type 'System.Data.Objects.ObjectQuery'.  'Select' not found.  Consider explicitly specifying the type of the range variable 'ats'."
    atsPlatform = ((from ats in platform select new AtsPlatform { RequestNumber = ats.RequestNumber, NumberOfFail = ats.NumberOfFail, NumberOfFailWithCR = ats.NumberOfFailWithCR, NumberOfTestCase = ats.NumberOfTestCase }).ToList());         

    return atsPlatform;
}

私のモデルクラスには、次のものがあります。

public class AtsPlatform
{
public string Name { get; set; }
public string RequestNumber { get; set; }
public Int32? NumberOfFail { get; set; }
public Int32? NumberOfTestCase { get; set; }
public Int32? NumberOfFailWithCR { get; set; }
}

データベースには、「ats1」、「ats2」、「ats3」..「atsN」というテーブルがあり、それぞれに「AtsPlatform」で定義されたプロパティと同じエンティティ フィールドがあります。

私がやりたいことは単純です:

List<AtsPlatform> a1 = GetAtsPlatformByName("ats1");
List<AtsPlatform> a2 = GetAtsPlatformByName("ats2");
List<AtsPlatform> aN = GetAtsPlatformByName("atsN");

「switch」を使用することもできますが、これによりコードの拡張性が低下し、新しい「ats(N+1)」が作成されるたびに更新が必要になります。

私の 2 日間の研究は、私をどこにも導きませんでした。私はかなり立ち往生しています。

助けてください!ありがとう!

4

3 に答える 3

1

リフレクションの代わりに、SqlQuery 関数を使用するのはどうですか?

そう

List<AtsPlatform> GetAtsPlatformByName(int index)
{
    using (var ctx = new Entities())
    {
        return ctx.Database.SqlQuery<AtsPlatform>("SELECT * FROM dbo.ats" + index)
                           .ToList();
    }
}

また、データベース オブジェクトの SqlQuery メソッドを使用したエンティティの変更追跡はありません (AtsPlatform クラスにはプリミティブ プロパティしか含まれていないため、これは問題ありません)。

変更の追跡には、DbSet SqlQuery メソッドを使用する必要があり、いくつかのリフレクションを混ぜる必要がある場合があります。

于 2013-10-08T22:48:18.450 に答える
1

さまざまなソリューションを試してみようと思ったので、返信が遅くなって申し訳ありません。

解決策 1: マスター テーブル

@Alexw で提案されているように、マスター テーブルの作成は、データベースのデザインを変更できる場合にのみ最適に機能します。現在、この変更を行うためにデータベースの所有者と協力しています。依存関係のため、この変更は次のフェーズまで待たなければなりません。

その間、私はこのアプローチを実行するためにモック db を作成しました。

解決策 #2: 生のクエリ

@Umair で提案されているように、生のクエリが機能します。生の SQL クエリを処理するクラスを作成しました。

public class AtsRawQuery
{
    private string ConnetionString = "";

    public AtsRawQuery(string connectionString)
    {
        this.ConnetionString = connectionString;
    }

    public List<List<string>> Query(string queryString)
    {
        List<List<string>> results = null;
        MySqlConnection conn = null;
        MySqlDataReader rdr = null;

        try
        {
            conn = new MySqlConnection(this.ConnetionString);
            conn.Open();

            MySqlCommand cmd = new MySqlCommand(queryString, conn);
            rdr = cmd.ExecuteReader();

            if (rdr.HasRows)
            {
                results = new List<List<string>>();
                while (rdr.Read())
                {
                    List<string> curr_result = new List<string>();
                    for (int columnIndex = 0; columnIndex <= rdr.FieldCount - 1; columnIndex++)
                    {
                        curr_result.Add(rdr.GetString(columnIndex));
                    }
                    results.Add(curr_result);
                }
            }
        }
        catch (MySqlException ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
        finally
        {
            if (rdr != null)
            {
                rdr.Close();
            }

            if (conn != null)
            {
                conn.Close();
            }

        }
        return results;
    }
}

このクラスは、後で使用するために 2 次元のリストを返します。

モデル クラスに、パーサー メソッドを追加しました。

public class AtsPlatform
{
    public string Name { get; set; }
    public string RequestNumber { get; set; }
    public Int32? NumberOfFail { get; set; }
    public Int32? NumberOfTestCase { get; set; }
    public Int32? NumberOfFailWithCR { get; set; }

    public void Parse(string name, string requestNumber, string numberOfFail, string numberOfTestCase, string numberOfFailWithCR)
    {
        Int32 temp;

        this.Name = name;
        this.RequestNumber = requestNumber;
        this.NumberOfFail = (Int32.TryParse(numberOfFail, out temp)) ? Int32.Parse(numberOfFail) : 0;
        this.NumberOfTestCase = (Int32.TryParse(numberOfTestCase, out temp)) ? Int32.Parse(numberOfTestCase) : 0;
        this.NumberOfFailWithCR = (Int32.TryParse(numberOfFailWithCR, out temp)) ? Int32.Parse(numberOfFailWithCR) : 0;
    }
}

解決策 #2(b): ExecuteStoreCommand を使用した生のクエリ

public List<AtsPlatform> GetAtsPlatformByName(string atsPlatformName)
    {
        List<AtsPlatform> atsPlatforms = null;
        string stm = String.Format("SELECT RequestNumber, NumberOfFail, NumberOfTestCase, NumberOfFailWithCR FROM {0}", atsPlatformName);

        atsPlatforms = new List<AtsPlatform>();
        foreach (AtsPlatform ats in ctx.ExecuteStoreQuery<AtsPlatform>(stm))
            {
                atsPlatforms.Add(ats);
            }

        return atsPlatforms;
    }

解決策 #3: ストアド プロシージャ

ストアド プロシージャを作成しました。コードは次のとおりです。

DELIMITER $$

CREATE PROCEDURE `UnionAtsTables`()
BEGIN

DECLARE atsName VARCHAR(10);   
DECLARE atsIndex INT; 

SET atsIndex = 1;       
SET @qry = '';

WHILE atsIndex > 0 DO 

    SET atsName =concat('ATS',atsIndex); 
    IF sf_is_table(atsName) = 1 THEN  
        Set @temp_qry = CONCAT('SELECT *, ''', atsName ,''' As TestPlatform FROM ', atsName, ' WHERE RequestNumber <> ''''' );
        If @qry = '' THEN
            SET @qry = @temp_qry;
        ELSE
            SET @qry = CONCAT(@qry, ' UNION ', @temp_qry);
        END IF;
    ELSE  
        SET atsIndex = -1;
    END IF;   

    SET atsIndex = atsIndex + 1;  

END WHILE;  

DROP TABLE IF EXISTS ats_all; 
SET @CreateTempTableQuery = CONCAT('CREATE TEMPORARY TABLE ats_all AS ', @qry ,'');
PREPARE stmt1 FROM @CreateTempTableQuery;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;

ALTER TABLE ats_all DROP COLUMN ExecOrder;
ALTER TABLE ats_all ADD ExecOrder INT PRIMARY KEY AUTO_INCREMENT;
ALTER TABLE ats_all auto_increment = 0;

END

テーブルがdbに存在するかどうかを確認する、オンラインで見つけた関数を次に示します。

DELIMITER $$

CREATE FUNCTION `sf_is_table`(`in_table` varchar(255)) RETURNS tinyint(4)
BEGIN 
/** 
* Check if table exists in database in use 
* 
* @name sf_is_table 
* @author Shay Anderson 08.13 <http://www.shayanderson.com> 
* 
* @param in_table (table name to check) 
* @return TINYINT (1 = table exists, 0 = table does not exist) 
*/ 

      # table exists flag 
      DECLARE is_table BOOLEAN DEFAULT FALSE; 

      # table count 
      DECLARE table_count INT DEFAULT 0; 

      # database name 
      SET @db = NULL; 

      # set database name 
      SELECT 
            DATABASE() 
      INTO 
            @db; 

      # check for valid database and table names 
      IF LENGTH(@db) > 0 AND LENGTH(in_table) > 0 THEN 

            # execute query to check if table exists in DB schema 
            SELECT COUNT(1) INTO table_count 
            FROM information_schema.`TABLES` 
            WHERE TABLE_SCHEMA = @db 
                  AND TABLE_NAME = in_table; 

            # set if table exists 
            IF table_count > 0 THEN 
                  SET is_table = TRUE; 
            END IF; 

      END IF; 

      RETURN is_table; 
END

結論:

ご提案いただきありがとうございます。ソリューション #2 を使用することにしました。これは、ソリューション #3 ほどデータベースのパフォーマンスに影響を与えず、ソリューション #1 のようにデータベースを再設計する必要がないためです。

于 2013-10-21T22:51:57.047 に答える
0

あなたがしていることはそのようにはうまくいかないと思います。単一の「マスター」テーブルに基づいてエンティティを作成する必要があります。Ats

これが完了すると、Entitiesクラスに というプロパティが作成されますAts。このプロパティを使用して、このような生の SQL クエリを使用してエンティティを選択できるようになりました。

var atsName = "ats1";

using (var context = new Entities())
{
    var blogs = context.Ats.SqlQuery(string.Format("SELECT * FROM {0}", atsName)).ToList();
}

または、これを試すこともできます(質問で指定していないため、プロパティタイプは DBSet であると想定しています)

var platform = propertyInfo.GetValue(ctx, null) as DBSet<Ats>;

atsPlatform = platform.Select(ats => new A new AtsPlatform { RequestNumber = ats.RequestNumber, NumberOfFail = ats.NumberOfFail, NumberOfFailWithCR = ats.NumberOfFailWithCR, NumberOfTestCase = ats.NumberOfTestCase }).ToList();     

return atsPlatform;
于 2013-10-08T22:49:20.143 に答える