前回の質問ではお世話になりました。
C#歴半年&MVC勉強したてですが、質問させていただきます。
今回はエラーメッセージの解決方法がわからず、質問させていただきたいと思います。
前提・実現したいこと
C#(ASP.NET Framework4.5.1 MVC)で履歴をExcel帳票出力するウェブアプリケーションを作っています。
コレクションに対してAddRangeを実装したいのですがうまく動きません。
発生している問題・エラーメッセージ
エラー 1 'System.Linq.IOrderedQueryable<A.Models.TEAM_HIS>' に 'AddRange' の定義が含まれておらず、型 'System.Linq.IOrderedQueryable<A.Models.TEAM_HIS>' の最初の引数を受け付ける拡張メソッドが見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足しています
ソースコード
namespace A.Models
{
using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
public partial class DefaultContext : DbContext
{
public DefaultContext()
: base("name=DefaultContext")
{
}
/// <summary>
/// プロジェクト経歴
/// </summary>
public virtual DbSet<TEAM_HIS> TEAM_HIS { get; set; }
/// <summary>
/// 変更履歴
/// </summary>
public virtual DbSet<CHANGE_HIS> CHANGE_HIS { get; set; }
}
}
namespace A.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class TEAM_HIS
{
[Key]
[Column(Order = 0)]
[StringLength(10)]
[DisplayName("team名")]
public string team { get; set; }
[Key]
[Column(Order = 1)]
[StringLength(10)]
[DisplayName("プロジェクト")]
public string project { get; set; }
[Key]
[Column(Order = 2)]
[DisplayName("開始日時")]
public DateTime start { get; set; }
[Key]
[Column(Order = 3)]
[DisplayName("終了日時")]
public DateTime end { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Data.Entity;
using A.Models;
namespace A.Report.History
{
/// <summary>
/// 個人履歴(Excel)出力
/// </summary>
public class HistoryGenerator : BaseReportGenerator
{
/// <summary>
/// コンストラクタ
/// </summary>
public ReportGeneratorService(DbSet dbcontext)
: base(dbcontext)
{}
public void Set()
{
DateTime start = new DateTime(1900, 1, 1);
DateTime next = new DateTime(1900, 1, 1);
int i_c = 1;
// 対象を設定します(今回は仮にAAAとします)
var target = (from t in DbContext.CHANGE_HIS
where t.name == "AAA"
orderby t.date ascending
select t).FirstOrDefault();
// CHANGE_HISの異動数を取得します
var m_c = (from m DbContext.CHANGE_HIS
where m.name == target.name
&& m.eve != "out"
select m).Count();
// outした対象のdateを取得します
var loss = (from l in DbContext.CHANGE_HIS
where l.name = target.name
&& l.eve = "out"
orderby l.date ascending
select l.date).FirstOrDefault();
// 履歴のコレクションで対象に異動がない場合の宣言
var col = from c in DbContext.TEAM_HIS
where c.team == target.team
orderby c.date, c.team ascending
select c;
// 一度データを消します
col = null;
// 履歴のコレクションを作成
foreach (var forlist in DbContext.TEAM_HIS)
{
start = (from s in DbContext.CHANGE_HIS
where s.team = forlist.team
&& s.date >= start
orderby s.date, no ascending
select s.date).FirstOrDefault();
if (m_c >= i_c)
{
next = (from n in DbContext.CHANGE_HIS
where n.team == forlist.team
&& n.date >= start
orderby n.date, n.team ascending
select n.date).FirstOrDefault();
}else{
next = DateTime.Now;
}
// TEAM毎の個人履歴をセット
var addcol = from a in DbContext.TEAM_HIS
where a.team == forlist.team
&& a.start < next
&& a.start >= start
&& a.start < loss
orderby a.start ascending
select a;
// 個人履歴に追加
addcol.AddRange(col);
++i_c;
foreach (var his in col)
{
var hist = new History(target);
hist.Name = target.name;
hist.Team = his.team;
hist.Project = his.project;
hist.Start = his.start;
hist.End = his.end;
target.Histories.Add(hist);
}
target.ColStartPos = cols;
cols += target.OutputWidth() + 1;
}
}
}
}
補足情報
TEAM_HISというプロジェクトの履歴を管理しているテーブルから、CHANGE_HISという個人の異動経歴を管理しているテーブルを結合させて、個人ごとのproject履歴を表示したExcelを出力したいというのが、実現したい機能です。
ソースはその一部を表示させています。
注意しなくてはいけないのは、対象者(name)が、TEAMを移ることがあること、TEAMに所属している間にlossする(管理対象外になる)ことがあること。
以上を考慮したところ、対象者があるTEAMに所属していた期間、start, nextで取得し、その期間のproject履歴を抽出する。そして、それを異動回数(CHANGE_HISのレコード数-1)だけ繰り返し、コレクションに追加していく。ただし、CHANGE_HISのレコードにoutが出てきたら、その日付までとする。
このような観点でプログラムを作成しています。
ところが、AddRangeを使用すると、表記のエラーが出てしまい解決できませんでした。
エラー自体の意味が理解できていなく、可能でありましたらエラーの意味と解決方法を教えていただけますでしょうか。
よろしくお願いいたします。
補足2
AddRangeをどう利用したいかですが、
// 1回目(本当はこれはaddcolではなく、colの形が望ましい)
addcol =
{
{T1, P01, 2013-5-1, 2013-8-10},
{T1, P02, 2013-8-21, 2013-12-20},
{T1, P03, 2014-1-11, 2014-3-30}
};
// 2回目(addcolは毎回上書きする)
addcol =
{
{T2, P01, 2014-5-1, 2014-8-10},
{T2, P08, 2014-8-21, 2015-3-30}
};
// 3回目
addcol =
{
{T3, P09, 2015-4-11, 2015-12-30}
};
// 合算後(addcolを3回目まで足しこむ)
col =
{
{T1, P01, 2013-5-1, 2013-8-10},
{T1, P02, 2013-8-21, 2013-12-20},
{T1, P03, 2014-1-11, 2014-3-30},
{T2, P04, 2014-5-1, 2014-8-10},
{T2, P08, 2014-8-21, 2015-3-30},
{T3, P09, 2015-4-11, 2015-12-30}
};
上記のような2次元配列を足しこんでいくようにしていきたいです。
※2つのテーブルと出力結果をアップローダーにあげておきます。
リンク内容
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
長くなりそうなので新しく回答します。
>>こちらで実装しようとしたAddRangeというメソッドは、System.collections.Genericに存在していますが、こちらではなく、A.Models.TEAM_HISにないか見に行っているということでしょうか。
オブジェクト指向をあまり理解されていないですかね?
と言うより、C#歴半年って書いてましたね。。。申し訳ないです。
System.collections.Genericをusingで呼び出したからと言ってそこに記述されているAddRangeがどこででも使用できるというわけではないです。
というよりも、System.Collections.Genericは名前空間なので中にメソッドは無いです。
リンクを参照してみてください。
>>すみません、理解が追い付いていませんが、addcolはTEAM_HISのコレクションであるから、この場合はAddRangeを使えないということになるのでしょうか。
コレクションという言い方がピンと来ないのですが、Linqをした結果を格納してますので
addcolの型はSystem.Linq.IOrderedQueryable<A.Models.TEAM_HIS>だと思われます。
前述したとおりSystem.Linq.IOrderedQueryableにAddRangeはないので使えないです。
>>colはaddcolでコレクションを追加していく空の入れ物として作りました。
元々のListなどのAddRangeでもNULLを追加することになり変ではないですか?
>>すみません、colとaddcolをLINQでの結合の仕方がわからないです。
もし可能でしたら教えていただけますと、AddRangeの問題ではない部分で解決できそうです。
下記コードを参照してみてください。
Dateの時間計算で長くなってしまいそうですが、1人1回のLinqで可能ではないでしょうか。
using System;
using System.Linq;
class Program
{
class 商品情報
{
public int Id;
public string 名前;
}
class 商品販売価格
{
public int Id;
public int 価格;
public string 店名;
}
static void Main(string[] args)
{
商品情報[] 商品情報データ =
{
new 商品情報() { Id = 1, 名前="PC-8001" },
new 商品情報() { Id = 2, 名前="MZ-80K" },
new 商品情報() { Id = 3, 名前="Basic Master Level-3" },
};
商品販売価格[] 商品販売価格データ =
{
new 商品販売価格() {Id=1, 価格=168000, 店名="BitOut"},
new 商品販売価格() {Id=1, 価格=148000, 店名="富士山音響"},
new 商品販売価格() {Id=2, 価格=178000, 店名="富士山音響"},
new 商品販売価格() {Id=3, 価格=298000, 店名="マイコンセンターROM"},
new 商品販売価格() {Id=3, 価格=229000, 店名="富士山音響"},
};
var query = from x in 商品情報データ
join y in 商品販売価格データ
on x.Id equals y.Id into z
select new { Name = x.名前, 商品データ = z };
foreach (var 商品 in query)
{
Console.WriteLine("{0}", 商品.Name);
foreach (var 価格情報 in 商品.商品データ)
{
Console.WriteLine("\t{0} {1:C}",
価格情報.店名, 価格情報.価格);
}
}
}
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
なんとなく理解が出来た気がするのでこちらに書かせていただきます。
最終的にされたいこととして、添付されてるエクセルの「出力データ」のように
4カラム+空白1カラム計5カラムで1人分で人数分を横につなげたい ということでよろしいでしょうか。
ごめんなさい、とんでもない勘違いをしていたようです。
下記のような感じでご理解いただけますでしょうか。
参照URL:DbContextを動的に使用する
using (var db = new DynamicDbContext("DynamicDbContext", type))
{
// DbSet<T>プロパティは無いのでSet()メソッドでDbSetインスタンスを取得
var dbSet = db.Set(type);
Console.WriteLine(dbSet.ElementType); // --> Person
dbSet.AddRange(newEntities);
db.SaveChanges();
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
単に各対象(人)ごとに集計を行ってそれをListに突っ込んでおいて
class result
{
public string Name;
public string Team;
public string Project;
public date Start;
public date End;
}
List<result> results = new List<result>();
それを各対象ごとに横展開すればいいだけじゃないんですか?
→レポート側の処理?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
何とかエラーを出なくして、それっぽい形にはなりました。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Data.Entity;
using A.Models;
namespace A.Report.History
{
/// <summary>
/// 個人履歴(Excel)出力
/// </summary>
public class HistoryGenerator : BaseReportGenerator
{
/// <summary>
/// コンストラクタ
/// </summary>
public ReportGeneratorService(DbSet dbcontext)
: base(dbcontext)
{}
public void Set()
{
DateTime start = new DateTime(1900, 1, 1);
DateTime next = new DateTime(1900, 1, 1);
int i_c = 1;
// 対象を設定します(今回は仮にAAAとします)
var target = (from t in DbContext.CHANGE_HIS
where t.name == "AAA"
orderby t.date ascending
select t).FirstOrDefault();
// CHANGE_HISの異動数を取得します
var m_c = (from m DbContext.CHANGE_HIS
where m.name == target.name
&& m.eve != "out"
select m).Count();
// outした対象のdateを取得します
var loss = (from l in DbContext.CHANGE_HIS
where l.name = target.name
&& l.eve = "out"
orderby l.date ascending
select l.date).FirstOrDefault();
// 出力対象の経歴コレクションの作成
var add_col = (from a in DbContext.TEAM_HIS
orderby a.date ascending
select a)
// AddRange関数を使用するためにList型にキャスト
List<TEAM_HIS> col = new List<TEAM_HIS>();
// 履歴のコレクションを作成
foreach (var forlist in t_col)
{
// カウントが1の時はnextが設定されていないため
if(i_c == 1);
{
start = (from s in DbContext.CHANGE_HIS
where s.team = forlist.team
&& s.date >= start
orderby s.date, no ascending
select s.date).FirstOrDefault();
}
else
{
start = next;
}
// カウントがMAXでない場合は計算する
if (m_c >= i_c)
{
// TEAMの移動が無い場合は次の時間をセット(ただし1回目は除く)
if(i_c != 1 & start == next)
{
next = (from n in DbContext.CHANGE_HIS
where n.team == forlist.team
&& n.date > start
orderby n.date, n.team ascending
select n.date).FirstOrDefault();
}else{
next = (from n in DbContext.CHANGE_HIS
where n.team == forlist.team
&& n.date >= start
orderby n.date, n.team ascending
select n.date).FirstOrDefault();
}
}else{
next = DateTime.Now;
}
// TEAM毎の個人履歴をセット
addcol = from a in DbContext.TEAM_HIS
where a.team == forlist.team
&& a.start < next
&& a.start >= start
&& a.start < loss
orderby a.start ascending
select a;
// 個人履歴に追加
if(addcol != null) col.AddRange(addcol);
++i_c;
}
foreach (var his in col)
{
var hist = new History(target);
hist.Name = target.name;
hist.Team = his.team;
hist.Project = his.project;
hist.Start = his.start;
hist.End = his.end;
target.Histories.Add(hist);
}
target.ColStartPos = cols;
cols += target.OutputWidth() + 1;
}
}
}
やり方としては、<TEAM_HIS>をList<>にキャスト?したのですが、
「最も適しているオーバーロード メソッドには無効な引数がいくつか含まれています。 」
というエラーが何度も出てきましたが、無事解決できました。
ただ、実際にデータが正しく出てくるかはまだ未知数なので、1日がかりのテストに取り掛かる予定です。
ご協力ありがとうございました。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
質問への追記・修正、ベストアンサー選択の依頼
pinnkoro
2016/03/09 14:46 編集
2点だけ質問を。
1.「AddRangeを実装したい」というのはTEAM_HISクラスにAddRangeメソッドを新しく作成したいということでしょうか?それともaddcolの後ろに要素をくっつけるようなListでいうAddRangeと同じ処理をさせたいのか。
2.DbSet の定義が書かれていないので分からないのですが、DbContext.TEAM_HISはどういう定義をされていますか?Listで書かれていますか?
pinnkoro
2016/03/09 15:06
自己解決
DinKa
2016/03/09 15:09
質問ありがとうございます
1.はい、後者です。おぼろげながら自分が勘違いしているのがわかったのですが、AddRangeメソッドはコレクションにコレクションを加えることはできないのでしょうか?
○リストA.AddRange(コレクションB)
×コレクションA.AddRange(コレクションB)
もしそうであれば、コレクションにコレクションを加えるような処理を実装するか、あるいは設計しなおすかになるかと思います。
2.DbSetの定義については、ご指摘いただいたTEAM_HISを本文に加えてみます。