データベースから入力された2つのDataTableがあります。1つはコアデータであり、もう1つは監査テーブルであり、コアデータのレコードが挿入、更新、または削除されたときに記録します。
注:削除されたレコードはコアデータには含まれませんが、監査履歴はあります。
最終的には、最新の「AUDITDATE」を持つ一意の「ID」のDataTableを取得し、その「AUDITDATE」の降順で並べ替えたいと思います。次に、最後に変更された一意のIDを降順で示すDataTableを作成できます。
「AUDITDATE」と「ID」はどちらも「yyyyMMddhhmmss」の形式のdoubleデータ型です。
だから私は3つのクエリを実行できると思っていました:
どのコアレコードが監査データに含まれていないか(触れられていないものを教えてくれます)
var setCore = new HashSet<double>(geometry.dtGEOM_TABLE_CORE.AsEnumerable().Select(p => p.Field<double>("ID")));
var setAudit = new HashSet<double>(geometry.dtGEOM_TABLE_AUDIT.AsEnumerable().Select(p => p.Field<double>("ID")));
var resultAuditInCore = geometry.dtGEOM_TABLE_AUDIT.AsEnumerable()
.Select(r => new { AUDITDATE = r.Field<double>("AUDITDATE"), ID = r.Field<double>("ID"), STATUS = "EXISTING" })
.Where(r => setCore.Contains(r.ID))
.OrderByDescending(r => r.AUDITDATE)
.GroupBy(r => r.ID)
.CopyToDataTable();
var resultAuditNotInCore = geometry.dtGEOM_TABLE_AUDIT.AsEnumerable()
.Select(r => new { AUDITDATE = r.Field<double>("AUDITDATE"), ID = r.Field<double>("ID"), STATUS = "DELETED" })
.Where(r => !setCore.Contains(r.ID))
.OrderByDescending(r => r.AUDITDATE)
.GroupBy(r => r.ID)
.CopyToDataTable();
var resultCoreNotInAudit = geometry.dtGEOM_TABLE_CORE.AsEnumerable()
.Select(r => new { AUDITDATE = (double)0, ID = r.Field<double>("ID"), STATUS = "NA" })
.Where(r => !setAudit.Contains(r.ID))
.OrderByDescending(r => r.ID)
.CopyToDataTable();
この後、「AUDITDATE」で3つすべての並べ替えを再度マージする予定でした。
問題:CopyToDataTable()は機能しませんが、削除すると機能します select()
質問:
あなたは、aの結果がGroupBy
一連のIGrouping<key, items>
オブジェクトであることに気づいていますね。各グループには、異なる数の要素が含まれる場合があります。このようなシーケンスは、データテーブルに変換できません。
MSDNにSystem.Data.DataTableExtensions.CopyToDataTable<T>
よると、ジェネリックパラメータTはDataRow
です。私のコンパイラは、匿名クラスがDataRowではないため、GroupByの結果をCopyToDataTableに入力できないと文句を言います。
したがって、変更されていない、削除された、監査されたアイテムを1つの順序付けられたシーケンスに変換DataRows
する必要があります。このシーケンスは、テーブルに必要なデータを含むものに変換できます。
コアデータテーブルのアイテムには少なくともIDがあり、監査データテーブルの要素には少なくとも。がありAuditDate
、CoreDataId
コアデータテーブルの監査済みアイテムのIDを参照していると仮定します(少なくともアイテムが存在します)。
どうやらあなたはすべてのデータを1つのテーブルに入れたいのですが、私はあなたがこのデータをオブジェクトに持っていると思いますTableData
。
変更されていないアイテムはのテーブルにないためAuditedData
、コアテーブルの変更されていないアイテムにはが必要TableData
です。
削除されたすべてのアイテムはコアデータに含まれなくなったため、AuditedDataテーブルの削除されたアイテムにもTableData
。が必要です。
すべてのデータをDateTimeで並べ替える必要があるためTableData
、AuditDateも含める必要があります。一部のアイテムは監査されません。それらのAuditDateはnullです。
TODO:監査されたことのないアイテムで並べ替える方法を決定しますか?注文した結果の最初または最後?*
class TableData
{
DateTime? AuditDate {get; set;} // used to order by date. null if never audited
...
}
class CoreData
{
public int Id {get; set;} // int may be any other type
public TableData {get; set;} // all untouched items should have this
// all others: choose what you want
...
}
class AuditData
{
public DateTime AuditDate {get; set;}
public int CoreId {get; set;}
public TableData {get; set;} // all deleted items should have this
// all others: choose what you want
...
}
IEnumerable<CoreData> coreData = ...
IEnumerable<AuditData> auditedData = ...
LINQクエリを作成して、元のコアデータと監査済みデータを最後に述べたシーケンスに変換できると思います。
触れられない(編集も削除もされない)
アイテム= coreDataにはあるが、auditedDataにはないすべてのアイテム:
var auditedItemIds = auditedData
.Select(auditedItem => auditedItem.CoreId)
.Distinct();
IEnumerable<TableData> untouchedItems = coreData
.Where(coreItem => !auditedItemIds.Contains(coreItem.Id))
.Select(coreItem => coreItem.TableData;
削除されたアイテム
= (もう)含まれauditedData
ていないすべてのアイテムcoreData
最後のauditedDataアイテムのみが必要です
var coreItemIds = coreData.Select(coreItem => coreItem.Id)
.Distinct();
IEnumerable<TableData> deletedItems = auditedData
// take only the audited items that are not in core data anymore:
.Where(auditedItem => !coreItemIds.Contains(auditedItem.CoreId)
// group the remaining items by same CoreId
.GroupdBy(
auditedItem => auditedItem.CoreId, // key of the group: coreId
autitedItem => auditedItem.TableData); // elements of the group
// from every group (= all audited items belonging to the same core item)
// take the element with the newest date
// = order by descending AuditDate and take FirstOrDefault
// because a group is created you are certain there is an element in the group
.Select(group => group
.OrderbyDescending(groupElement => groupElement.AuditDate)
.FirstOrDefault());
編集項目は
=の両方にあるすべてのアイテムcoreData
とでは、auditedData
あなたがしたい場合、私はわからないtableData
からcoreData
やからをauditedData
。LINQクエリも同様です。
tableData
最新の監査からのものが必要だと仮定します。
var coreItemIds = coreData.Select(coreItem => coreItem.Id)
.Distinct();
IEnumerable<TableData> newestAuditData = auditedData
// take only auditedData that is still in coreData
.Where(auditedItem => coreItemIds.Contains(auditedItem.CoreId)
// group the remaining items by same CoreId
.GroupdBy(
auditedItem => auditedItem.CoreId, // key of the group: coreId
autitedItem => auditedItem.TableData); // elements of the group
// from every group (= all audited items belonging to the same core item)
// take the element with the newest date
// = order by descending AuditDate and take FirstOrDefault
// because a group is created you are certain there is an element in the group
.Select(group => group
.OrderbyDescending(groupElement => groupElement.AuditDate)
.FirstOrDefault());
後の表現Where
は、削除されたアイテムでも監査対象のアイテムと同じであることに気づきましたか?
これで、これらすべての要素を並べ替える方法を決定し、それらをDataRowの1つのシーケンスに配置するだけです。
IOrderedEnumerable<TableData> OrderQueryResult(
IEnumerable<TableData> unTouchedItems,
IEnumerable<TableData> deletedItems,
IEnumerable<TableData> auditedItems)
{
// TODO decide what order to use
return result;
}
class MyDataRow : DataRow
{
MyDataRow(TableData tableData)
{
// in the constructor, extract the data you want in the DataRow
}
}
IOrderedEnumerable<TableData> orderedTableData = OrderedQueryResult(
untouchedItems, deletedItems, newestAuditData);
IEnumerable<MyDataRow> dataRows = orderedTableData
.Select(tableData => new MyDataRow(tableData);
DataTable myTable = dataRows.CopyToDataTable();
最後に、データベースがすでに存在するのか、それとも現在開発中なのかはわかりません。同じデータを含む2つのテーブルがあるため、クエリは非常に困難です。1つは実際のデータを含み、もう1つはデータの履歴を含みます。次のテーブルがあれば、クエリははるかに簡単でした。
私はこれをEntity-Framework形式で記述します。他の方法を使用する場合は、そこからSQLテーブルを抽出できると確信しています。
class CoreData
{
public int Id {get; set;}
public ... NeverChangingItems {get; set;}
public bool IsObsolete {get; set;}
// HistoricData is data that might change through history
public virtual ICollection<HistoricData> HistoricData {get; set;}
}
public class HistoricData
{
public int Id {get; set;}
public DateTime AuditDate {get; set;}
public ... ItemsThatChangeThroughoutHistory {get; set;}
// foreign key to owning Core
public int CoreDataId {get; set;}
public virtual CoreData CoreData {get; set;}
}
変更されないコアデータを含むテーブルと履歴を含むテーブルがある場合、3つのクエリははるかに簡単になります。さらに、要素が削除されることはないため、変更されていないコアデータのコピーを用意する必要はありません。
使用する方法では、削除されたアイテムも監査済みテーブルに残っているため、実際には削除されないことに注意してください。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加