請教各位前輩,不好意思,以下問題的敍述可能有點詞不達意,就先且戰且走再補充說明。
問題:以下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的寫法來解決也可以分享,感激不盡了~
檢查一下
如果因為開頭大小寫或底線導致的問題,會不會想翻桌砸電腦?? XDDD
問題如樓上的大大所述喔,只是不知道是否有更好的解法~
您是轉型成特定的類別物件,想到一個爛方法....
假設您要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";
另一個做法就是往預設值的方向走~~~(沒實測)
在類別設定預設值,EF也設好預設值,不過sql中主鍵值一定要撈出來,不然EF應該過不了
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實體名稱 我根據你提供的資訊推敲的 還要再檢查一下
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則陸續將相關角色清單列出~
感謝大師指點~
我不是大師 只是小菜雞
我大概知道需求了 晚點幫你試一下 現在還在忙
嗨 我回來了 抱歉忙完就忘記了
不知道你問題解決了沒
以下是我用我自己的資料測試的 語法跟流程再給你參考看看
不過好像變得更複雜
第一個方法:
// 模擬你的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();
是不是加入MermerID就好了?
因為你的MermerID是主鍵,
另外 * 可以用但是會某種程度地影響效率,
正常來說本來就是你所有需要的欄位都要列出來,
這你要早點適應會比較好.
報告:有測試加入MermerID就好,但這樣是不行的,一樣會將你沒列出的欄位報錯。
目前測試就是要將Member這個Table裡的欄位全部都列出才OK~
你的結構是VS自動產生的?
看你這個程式碼應該也不需要用到Entity,
或許是你少了預設值,
如果在結構那邊加上預設值也許可以?
另外如果你只要E-mail而已,
或許可以直接用
var result = db.Database.SqlQuery<string>(sql,
new SqlParameter("ConferenceId", ConferenceId)).ToList();
接資料?
1.結構是指DB嗎?DB是用edmx建立的.
2.(程式碼應該也不需要用到Entity),請問什麼樣的程式才適合用Entity呢?
3.(或許是你少了預設值,如果在結構那邊加上預設值也許可以?),因為不懂您指的結構是什麼?所以也不了解該如何設定預設值,請問要在那中裡設定呢?
4.大師建議的程式碼可以運作喔,原來這個語法是這樣使用的,受教了,謝謝~
var result = db.Database.SqlQuery<string>(sql,
new SqlParameter("ConferenceId", ConferenceId)).ToList();
5.這個需求還是想要求解lambda要怎麼寫~
他只是把結果轉換成你的結構(class),
你去看edmx產生的那些其實也是class,
只是事先幫你產生好而已,
string也是C#預設的一個class,
用法是一樣的,
至於初始化(預設值)的部分,
這算是C#的基礎,
你去查一下C#的class和一些基本的內容,
補充一下基本觀念.
至於lambda我比較少在用,
我記得其他邦友好像有回答這部分.
如果預設值是指類別初始化這件事的話,那就我的理解是不是應該是指類別的constructor,因為DB的class都是edmx幫忙自動產生的,所以如果是這樣的狀況,是指我要去新增異動這些自動產生的class來設定constructor預設值嗎?
有時候我會去改它產生的,
如果不改也是可以,
可能就要像你這樣全部列出來吧.