iT邦幫忙

0

關於ASP.NET SQL查詢錯誤問題

請教各位前輩,不好意思,以下問題的敍述可能有點詞不達意,就先且戰且走再補充說明。
問題:以下SQL語法若寫SELECT * 是可以正常執行的,但若指定欄位執行則會出現如下錯誤訊息。

string sql = @"SELECT m.Email
              FROM MemberToConference AS mtc 
              JOIN Members AS m ON mtc.MemberId = m.MemberId
              WHERE mtc.ConferenceId = @ConferenceId";

if (Roles.Length == 1)
{
    sql += @" AND mtc.Role = '" + Roles[0] + "'";
}
else
{
    for (int i = 0; i < Roles.Length; i++)
    {
        if (i == 0)
        {
            sql += @" AND (mtc.Role = '" + Roles[i] + "'";
        }
        else if (i == (Roles.Length - 1))
        {
            sql += @" OR mtc.Role = '" + Roles[i] + "')";
        }
        else
        {
            sql += @" OR mtc.Role = '" + Roles[i] + "'";
        }
    }
}
var result = db.Database.SqlQuery<Member>(sql,
    new SqlParameter("ConferenceId", ConferenceId)).ToList();

錯誤訊息如下:

'/' 應用程式中發生伺服器錯誤。
資料讀取器與指定的 'SubmissionModel.Member' 不相容。該型別的成員 'MemberId' 在相同名稱的資料讀取器中沒有對應的資料行。
描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。

例外狀況詳細資訊: System.Data.Entity.Core.EntityCommandExecutionException: 資料讀取器與指定的 'SubmissionModel.Member' 不相容。該型別的成員 'MemberId' 在相同名稱的資料讀取器中沒有對應的資料行。

原始程式錯誤:


行 231:                }
行 232:            }
行 233:            var result = db.Database.SqlQuery<Member>(sql,
行 234:                new SqlParameter("ConferenceId", ConferenceId)).ToList();
行 235:            foreach (var obj in result)

需求:主要是想要寫DISTINCT m.Email,把重複的Email過濾掉
但不知為何在var result = db.Database.SqlQuery(sql,
new SqlParameter("ConferenceId",
這一段程式碼會發生錯誤

SqlQuery<Member>

但不知道該如何修正為我的需求
或各位前輩如果知道以上查詢需求,該如何改寫為Lambda或LINQ的寫法來解決也可以分享,感激不盡了~

看更多先前的討論...收起先前的討論...
你沒有SELECT MEMBER_ID 阿@@
看一下你的型別MEMBER裡面啥欄位 SELECT 都要有
leo226 iT邦新手 5 級 ‧ 2020-01-31 15:46:00 檢舉
如大大所言,型別MEMBER裡面啥欄位 SELECT 都要有,所以把所有欄位都放進來就OK了,但實在是麻煩:
string sql = @"SELECT m.Email, m.MemberId, m.Account, m.Password, m.Name, m.FirstName, m.LastName, m.MemberTitle, m.Gender, m.EmailAuthCode, m.Phone, m.Mobile, m.Department, m.Country, m.ProfessionalFieldName, m.AuthId, m.RegisterTime, m.LastUpdateTime, m.LastLoginTime, m.Disabled
FROM MemberToConference AS mtc
JOIN Members AS m ON mtc.MemberId = m.MemberId
WHERE mtc.ConferenceId = @ConferenceId";

請問我只需要Email的資訊並且把重複的排除掉,一定要把全部欄位寫出來嗎?是否有更好的解法?
目前測試就是再建一個ViewModel,裡面只有放Email這個欄位,然後套用進去
db.Database.SqlQuery<GetEmailViewModel>(sql,
new SqlParameter("ConferenceId", ConferenceId)).ToList();
如此大費周張的做法,實在是有點小麻煩,不知是否有更好的方法可用呢?
那你就直接轉一個dataTable就好 不要轉型成MEMBER物件
1
舜~
iT邦高手 1 級 ‧ 2020-01-31 14:56:35

檢查一下

  1. 你的Entity欄位與資料庫欄位並不同步,把你的Entity更新一下
  2. 原本就沒有MemberId欄位

如果因為開頭大小寫或底線導致的問題,會不會想翻桌砸電腦?? XDDD
/images/emoticon/emoticon40.gif

leo226 iT邦新手 5 級 ‧ 2020-01-31 15:47:48 檢舉

問題如樓上的大大所述喔,只是不知道是否有更好的解法~

舜~ iT邦高手 1 級 ‧ 2020-01-31 16:11:23 檢舉

您是轉型成特定的類別物件,想到一個爛方法....
假設您要Email、MemberId

string sql = @"SELECT m.Email, m.MemberId, '' Account, '' Password, '' Name, '' FirstName, '' LastName, '' MemberTitle, '' Gender, '' EmailAuthCode, '' Phone, '' Mobile, '' Department, '' Country, '' ProfessionalFieldName, '' AuthId, '' RegisterTime, '' LastUpdateTime, '' LastLoginTime, '' Disabled
FROM MemberToConference AS mtc
JOIN Members AS m ON mtc.MemberId = m.MemberId
WHERE mtc.ConferenceId = @ConferenceId";

舜~ iT邦高手 1 級 ‧ 2020-01-31 16:13:26 檢舉

另一個做法就是往預設值的方向走~~~(沒實測)
在類別設定預設值,EF也設好預設值,不過sql中主鍵值一定要撈出來,不然EF應該過不了

0
w4560000
iT邦新手 4 級 ‧ 2020-02-03 11:29:59

lambda

string ConferenceId = "xxx";
var result = db.MemberToConference
               .Join(
                   db.Members, 
                   x => x.MemberId, 
                   z => z.MemberId, (x, z) => new { x.ConferenceId, z.Email })
               .Where(w => w.ConferenceId.Equals(ConferenceId)
               .Select(s => s.Email)
               .ToList();

試一下看看 若一定要用Sql語法的話


string sql = @"SELECT * FROM MemberToConference AS mtc
               JOIN Members AS m ON mtc.MemberId = m.MemberId
               WHERE mtc.ConferenceId = @ConferenceId";
string ConferenceId = "xxx";

var result = db.Database.SqlQuery<Member>(sql,
                 new SqlParameter(
                     nameof(MemberToConference.ConferenceId), 
                     ConferenceId))
                .Select(s => s.Email).ToList();

Entity實體名稱 我根據你提供的資訊推敲的 還要再檢查一下

leo226 iT邦新手 5 級 ‧ 2020-02-03 12:03:57 檢舉

lambda的部份,我不會寫的是以下這一段,不知道該如何依判斷式加入~

if (Roles.Length == 1)
{
    sql += @" AND mtc.Role = '" + Roles[0] + "'";
}
else
{
    for (int i = 0; i < Roles.Length; i++)
    {
        if (i == 0)
        {
            sql += @" AND (mtc.Role = '" + Roles[i] + "'";
        }
        else if (i == (Roles.Length - 1))
        {
            sql += @" OR mtc.Role = '" + Roles[i] + "')";
        }
        else
        {
            sql += @" OR mtc.Role = '" + Roles[i] + "'";
        }
    }
}

大師提供的參考是第一段主要的SQL,這一段轉成lambda我是可以的~

string sql = @"SELECT m.Email
              FROM MemberToConference AS mtc 
              JOIN Members AS m ON mtc.MemberId = m.MemberId
              WHERE mtc.ConferenceId = @ConferenceId";

需求就是會有一個Role陣列參數傳進來,若有多個Role則陸續將相關角色清單列出~
感謝大師指點~

w4560000 iT邦新手 4 級 ‧ 2020-02-03 13:37:58 檢舉

我不是大師 只是小菜雞/images/emoticon/emoticon16.gif

我大概知道需求了 晚點幫你試一下 現在還在忙

w4560000 iT邦新手 4 級 ‧ 2020-02-05 15:24:25 檢舉

嗨 我回來了 抱歉忙完就忘記了
不知道你問題解決了沒
以下是我用我自己的資料測試的 語法跟流程再給你參考看看
不過好像變得更複雜
/images/emoticon/emoticon10.gif

第一個方法:

// 模擬你的Role陣列
int[] intArray = { 1101, 1102, 1103, 1104 };

            var d1 = a.Stock.Join(a.StockDay, x => x.StockNo, z => z.StockNO,
               (x, z) => new ViewModel { no = x.StockNo, name1 = z.StockNO })
                //這行你可以換成ConferenceId的比對
                //.Where(w => w.StockNo.Equals(1101))
                .Where(WhereCondition<ViewModel>(intArray, nameof(ViewModel.no)))
                .Select(s => s.no).ToList();

// 用你的Role陣列來判斷查詢條件
 public static Expression<Func<T, bool>> WhereCondition<T>(int[] array, string leftPropertyName)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T));
            Expression left = Expression.Property(parameter, leftPropertyName);
            Expression a = null;

            for (int i = 0; i < array.Length; i++)
            {
                if (i == 0)
                {
                    a = Expression.Equal(left, Expression.Constant(array[i], array[i].GetType()));
                }
                else
                {
                    a = Expression.Or(a, Expression.Equal(left, Expression.Constant(array[i], array[i].GetType())));
                }
            }

            return Expression.Lambda<Func<T, bool>>(a, parameter);
        }

第二個方法:

// StockName你可以改成ConferenceId的比對
// intArray換成你的RoleArray
 var test = a.Stock.Join(a.StockDay, x => x.StockNo, z => z.StockNO,
               (x, z) => new { x.StockName, z.StockNO })
                .Where(w => w.StockName == "test" && intArray.Contains(w.StockNO)).ToList();
0
小魚
iT邦大師 1 級 ‧ 2020-02-04 13:16:29

是不是加入MermerID就好了?
因為你的MermerID是主鍵,

另外 * 可以用但是會某種程度地影響效率,
正常來說本來就是你所有需要的欄位都要列出來,
這你要早點適應會比較好.

看更多先前的回應...收起先前的回應...
leo226 iT邦新手 5 級 ‧ 2020-02-04 15:21:10 檢舉

報告:有測試加入MermerID就好,但這樣是不行的,一樣會將你沒列出的欄位報錯。
目前測試就是要將Member這個Table裡的欄位全部都列出才OK~

小魚 iT邦大師 1 級 ‧ 2020-02-04 15:32:12 檢舉

你的結構是VS自動產生的?
看你這個程式碼應該也不需要用到Entity,
或許是你少了預設值,
如果在結構那邊加上預設值也許可以?

另外如果你只要E-mail而已,
或許可以直接用

var result = db.Database.SqlQuery<string>(sql,
    new SqlParameter("ConferenceId", ConferenceId)).ToList();

接資料?

leo226 iT邦新手 5 級 ‧ 2020-02-05 10:24:12 檢舉

1.結構是指DB嗎?DB是用edmx建立的.
2.(程式碼應該也不需要用到Entity),請問什麼樣的程式才適合用Entity呢?
3.(或許是你少了預設值,如果在結構那邊加上預設值也許可以?),因為不懂您指的結構是什麼?所以也不了解該如何設定預設值,請問要在那中裡設定呢?
4.大師建議的程式碼可以運作喔,原來這個語法是這樣使用的,受教了,謝謝~

var result = db.Database.SqlQuery<string>(sql,
    new SqlParameter("ConferenceId", ConferenceId)).ToList();

5.這個需求還是想要求解lambda要怎麼寫~

小魚 iT邦大師 1 級 ‧ 2020-02-05 13:18:14 檢舉

他只是把結果轉換成你的結構(class),
你去看edmx產生的那些其實也是class,
只是事先幫你產生好而已,
string也是C#預設的一個class,
用法是一樣的,

至於初始化(預設值)的部分,
這算是C#的基礎,
你去查一下C#的class和一些基本的內容,
補充一下基本觀念.

至於lambda我比較少在用,
我記得其他邦友好像有回答這部分.

leo226 iT邦新手 5 級 ‧ 2020-02-05 16:36:20 檢舉

如果預設值是指類別初始化這件事的話,那就我的理解是不是應該是指類別的constructor,因為DB的class都是edmx幫忙自動產生的,所以如果是這樣的狀況,是指我要去新增異動這些自動產生的class來設定constructor預設值嗎?

小魚 iT邦大師 1 級 ‧ 2020-02-05 21:08:59 檢舉

有時候我會去改它產生的,
如果不改也是可以,
可能就要像你這樣全部列出來吧.

我要發表回答

立即登入回答