Need more efficient way to convert Entities to DataTable - entity-framework

So, I have a method that converts entities into a DataTable. The only problem is it is very slow. I made sure to call .ToList() on the IQueryable to make it go ahead and load before processing the results into a DataTable. It takes hardly any time to load the 3000+ rows into memory. However, the real time slayer is in the following iteration in the method:
foreach (var index in imgLeaseIndexes)
{
DataRow dataRow = dataTable.NewRow();
dataRow["StateCode"] = index.StateCode;
dataRow["CountyCode"] = index.CountyCode;
dataRow["EntryNumber"] = index.EntryNumber;
dataRow["Volume"] = index.Volume;
dataRow["Page"] = index.Page;
dataRow["PageCount"] = index.ImgLocation.PageCount;
dataRow["CreateDate"] = index.ImgLocation.CreateDate;
dataTable.Rows.Add(dataRow);
}
And here is the complete method, for what it's worth:
private DataTable buildImgLeaseIndexDataTable(List<ImgLeaseIndex> imgLeaseIndexes)
{
var dataTable = new DataTable();
var dataColumns = new List<DataColumn>();
var tdiReportProperties =
new List<string>() { "StateCode", "CountyCode", "EntryNumber", "Volume", "Page", "PageCount", "CreateDate" };
Type imgLeaseIndexType = imgLeaseIndexes.FirstOrDefault().GetType();
PropertyInfo[] imgLeaseIndexPropertyInfo = imgLeaseIndexType.GetProperties();
dataColumns.AddRange(
(from propertyInfo in imgLeaseIndexPropertyInfo
where tdiReportProperties.Contains(propertyInfo.Name)
select new DataColumn()
{
ColumnName = propertyInfo.Name,
DataType = (propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) ?
propertyInfo.PropertyType.GetGenericArguments()[0] : propertyInfo.PropertyType
})
.ToList());
Type imgLocationType = imgLeaseIndexes.FirstOrDefault().ImgLocation.GetType();
PropertyInfo[] imgLocationPropertyInfo = imgLocationType.GetProperties();
dataColumns.AddRange(
(from propertyInfo in imgLocationPropertyInfo
where tdiReportProperties.Contains(propertyInfo.Name)
select new DataColumn()
{
ColumnName = propertyInfo.Name,
DataType = (propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) ?
propertyInfo.PropertyType.GetGenericArguments()[0] : propertyInfo.PropertyType
})
.ToList());
dataTable.Columns.AddRange(dataColumns.ToArray());
foreach (var index in imgLeaseIndexes)
{
DataRow dataRow = dataTable.NewRow();
dataRow["StateCode"] = index.StateCode;
dataRow["CountyCode"] = index.CountyCode;
dataRow["EntryNumber"] = index.EntryNumber;
dataRow["Volume"] = index.Volume;
dataRow["Page"] = index.Page;
dataRow["PageCount"] = index.ImgLocation.PageCount;
dataRow["CreateDate"] = index.ImgLocation.CreateDate;
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
Does anyone have ideas on how I can make this more efficient and why it is so slow as is?
UPDATE:
I removed the reflection and explicitly set the data columns at compile time per the feedback I've received so far, but it is still really slow. This is what the updated code looks like:
private DataTable buildImgLeaseIndexDataTable(List<ImgLeaseIndex> imgLeaseIndexes)
{
var dataTable = new DataTable();
var stateCodeDataColumn = new DataColumn();
stateCodeDataColumn.ColumnName = "StateCode";
stateCodeDataColumn.Caption = "State Code";
stateCodeDataColumn.DataType = typeof(Int16);
dataTable.Columns.Add(stateCodeDataColumn);
var countyCodeDataColumn = new DataColumn();
countyCodeDataColumn.ColumnName = "CountyCode";
countyCodeDataColumn.Caption = "County Code";
countyCodeDataColumn.DataType = typeof(Int16);
dataTable.Columns.Add(countyCodeDataColumn);
var entryNumberDataColumn = new DataColumn();
entryNumberDataColumn.ColumnName = "EntryNumber";
entryNumberDataColumn.Caption = "Entry Number";
entryNumberDataColumn.DataType = typeof(string);
dataTable.Columns.Add(entryNumberDataColumn);
var volumeDataColumn = new DataColumn();
volumeDataColumn.ColumnName = "Volume";
volumeDataColumn.DataType = typeof(string);
dataTable.Columns.Add(volumeDataColumn);
var pageDataColumn = new DataColumn();
pageDataColumn.ColumnName = "Page";
pageDataColumn.DataType = typeof(string);
dataTable.Columns.Add(pageDataColumn);
var pageCountDataColumn = new DataColumn();
pageCountDataColumn.ColumnName = "PageCount";
pageCountDataColumn.Caption = "Page Count";
pageCountDataColumn.DataType = typeof(string);
dataTable.Columns.Add(pageCountDataColumn);
var createDateDataColumn = new DataColumn();
createDateDataColumn.ColumnName = "CreateDate";
createDateDataColumn.Caption = "Create Date";
createDateDataColumn.DataType = typeof(DateTime);
dataTable.Columns.Add(createDateDataColumn);
foreach (var index in imgLeaseIndexes)
{
DataRow dataRow = dataTable.NewRow();
dataRow["StateCode"] = index.StateCode;
dataRow["CountyCode"] = index.CountyCode;
dataRow["EntryNumber"] = index.EntryNumber;
dataRow["Volume"] = index.Volume;
dataRow["Page"] = index.Page;
dataRow["PageCount"] = index.ImgLocation.PageCount;
dataRow["CreateDate"] = index.ImgLocation.CreateDate;
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
Any ideas on what else might be causing this?
UPDATE 2:
So it looks like other people have had this problem - specific to creating and setting the DataRows. My co-worker came across this:
The DataRow value setter is slow!
I'm going to try some of the stuff suggested in the link.

As Thiago mentioned in the comments the problem is the use of reflection.
The reflection part is where you are using PropertyInfo. You are getting the structure of the data types at runtime. But these are known at compile time.

Related

Error VS403357 when batch creating many work items in Azure DevOps using .NET API

I'm trying to use the Azure DevOps .NET API to batch create WorkItems in a AzureDevOps repository, but when I submit the batch request, I'm getting back an error message: "VS403357: Work items in the batch are expected to be unique, but found work item with ID -1 in more than one request."
Here's my code:
public void ExecuteWorkItemMigration(int[] workItemIds, IProgress<ProgressResult> progress = null)
{
var wiql = "SELECT * FROM WorkItems";
var query = new Query(_workItemStore, wiql, workItemIds);
var workItemCollection = query.RunQuery();
string projectName = MainSettings.AzureDevOpsSettings.ProjectName;
List<WitBatchRequest> batchRequests = new List<WitBatchRequest>();
foreach (WorkItemTfs tfsWorkItem in workItemCollection)
{
JsonPatchDocument document = CreateJsonPatchDocument(tfsWorkItem);
string workItemType = GetWorkItemType(tfsWorkItem);
WitBatchRequest wibr = _azureDevopsWorkItemTrackingClient.CreateWorkItemBatchRequest(projectName, workItemType,
document, true, true);
batchRequests.Add(wibr);
}
List<WitBatchResponse> results = _azureDevopsWorkItemTrackingClient.ExecuteBatchRequest(batchRequests).Result;
}
private static JsonPatchDocument CreateJsonPatchDocument(WorkItemTfs tfsWorkItem, int id = -1)
{
var document = new JsonPatchDocument();
document.Add(
new JsonPatchOperation
{
Path = "/id",
Operation = Operation.Add,
Value = id
});
document.Add(
new JsonPatchOperation
{
Path = "/fields/System.Title",
Operation = Operation.Add,
Value = tfsWorkItem.Title
});
if (tfsWorkItem.Fields.Contains("ReproSteps"))
document.Add(
new JsonPatchOperation
{
Path = "/fields/Microsoft.VSTS.TCM.ReproSteps",
Operation = Operation.Add,
Value = tfsWorkItem.Fields["ReproSteps"].Value
});
}
Any suggestions about what I need to do to get this working properly?
I have tried submitting different unique ID's but it doesn't seem to prevent the error from happening.
You need to use unique negative ID's for creating the WorkItem ID.
Something like this:
public void ExecuteWorkItemMigration(int[] workItemIds, IProgress<ProgressResult> progress = null)
{
var wiql = "SELECT * FROM WorkItems";
var query = new Query(_workItemStore, wiql, workItemIds);
var workItemCollection = query.RunQuery();
string projectName = MainSettings.AzureDevOpsSettings.ProjectName;
List<WitBatchRequest> batchRequests = new List<WitBatchRequest>();
int id = -1;
foreach (WorkItemTfs tfsWorkItem in workItemCollection)
{
JsonPatchDocument document = CreateJsonPatchDocument(tfsWorkItem, id--);
string workItemType = GetWorkItemType(tfsWorkItem);
WitBatchRequest wibr = _azureDevopsWorkItemTrackingClient.CreateWorkItemBatchRequest(projectName, workItemType,
document, true, true);
batchRequests.Add(wibr);
}
List<WitBatchResponse> results = _azureDevopsWorkItemTrackingClient.ExecuteBatchRequest(batchRequests).Result;
}

When using NumericField, get absolutely nothing back every time

Been playing with Lucene.NET the last two days.
After reading up on Dates, I was led to believe that Dates are best converted to Milliseconds, and stored in NumericField, with Indexing=true, and Store=No.
But now nothing ever returns - it must be something basic, but I'm just not seeing it.
The saving code is as follows:
...
else if (type == typeof (DateTime?))
{
var typedValue = (DateTime?) value;
field = numericField = new NumericField(documentFieldName, 4, Field.Store.YES, true);
long milliseconds = typedValue.HasValue?(typedValue.Value.Date.Ticks/TimeSpan.TicksPerMillisecond):0;
numericField.SetLongValue(milliseconds);
doc.Add(numericField);
}
...
else
{
field = stringField = new Field(
documentFieldName,
(value != null)?value.ToString():string.Empty,
Store.YES,
Field.Index.ANALYZED) ;
doc.Add(stringField);
}
// Write the Document to the catalog
indexWriter.AddDocument(doc);
When I query for docs against the values saved in Field ... no problem.
When I query for documents by matching against the values in NumericFields, nothing returns.
Where did I go wrong?
Thanks for your help.
Lucene.Net.Analysis.Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
var q2 = NumericRangeQuery.NewLongRange("Val", 3, 3, true, true);
var uxy2 = documentSearchManagementService.Search("Students", termQuery, "Id");
Using:
public ScoredDocumentResult[] Search(string indexName, Query query, params string[] hitFieldNamesToReturn)
{
if (_configuration.IndexRootDirectory.IsNullOrEmpty())
{
throw new Exception("Configuration.IndexRootDirectory has not been configued yet.");
}
indexName.ValidateIsNotNullOrEmpty("indexName");
hitFieldNamesToReturn.ValidateIsNotDefault("hitFieldNamesToReturn");
//Specify the index file location where the indexes are to be stored
string indexFileLocation = Path.Combine(_configuration.IndexRootDirectory, indexName);
Lucene.Net.Store.Directory luceneDirectory = Lucene.Net.Store.FSDirectory.Open(indexFileLocation);
IndexSearcher indexSearcher = new IndexSearcher(luceneDirectory);
TopScoreDocCollector topScoreDocCollector = TopScoreDocCollector.Create(10, true);
indexSearcher.Search(query, topScoreDocCollector);
List<ScoredDocumentResult> results = new List<ScoredDocumentResult>();
foreach (var scoreDoc in topScoreDocCollector.TopDocs(0, 10).ScoreDocs)
{
ScoredDocumentResult resultItem = new ScoredDocumentResult();
Lucene.Net.Documents.Document doc = indexSearcher.Doc(scoreDoc.Doc);
resultItem.Score = scoreDoc.Score;
List<ScoredDocumentFieldResult> fields = new List<ScoredDocumentFieldResult>();
foreach (string fieldName in hitFieldNamesToReturn)
{
string fieldValue = doc.Get(fieldName);
fields.Add(new ScoredDocumentFieldResult{Key= fieldName,Value=fieldValue});
}
resultItem.FieldValues = fields.ToArray();
results.Add(resultItem);
}
indexSearcher.Close();
return results.ToArray();
}

Append divs changing his content dynamic

I have a dif called cdefualt that has some inputs from a form inside of it and I want to do something like this to clone it and change that input names:
var i = 2;
function add() {
var item = $('#cdefault').clone();
item.attr({'style': ''});
$xpto = 'gtitle'+i;
$xpto2 = 'gmessage'+i;
item.id = $xpto;
$('#'+$xpto+' input[id="gtitle1"]').attr('name', $xpto);
$('#'+$xpto+' textarea[id="gmessage1"]').attr('name',$xpto2);
$(item).appendTo('#ccontainer');
i++;
}
But this doesnt work. I've tried this already as well but it only works twice (for the original and first clone):
var i = 2;
function add() {
var item = $('#cdefault').clone();
item.attr({'style': ''});
$xpto = 'gtitle'+i;
$xpto2 = 'gmessage'+i;
$('#cdefault input[id="gtitle1"]').attr('id', $xpto);
$('#cdefault textarea[id="gmessage1"]').attr('id',$xpto2);
$('#cdefault input[name="gtitle1"]').attr('name', $xpto);
$('#cdefault textarea[name="gmessage1"]').attr('name', $xpto2);
$(item).appendTo('#ccontainer');
i++;
}
Even tryed this way:
function add() {
$xpto = 'gtitle'+i;
$xpto2 = 'gmessage'+i;
var div = document.getElementById('cdefault');
clone = div.cloneNode(true); // true means clone all childNodes and all event handlers
clone.id = $xpto;
clone.style.display = '';
$("#"+$xpto+" input[id='gtitle1']").attr('name', $xpto);
$("#"+$xpto+" textarea[id='gmessage1']").attr('name',$xpto2);
document.getElementById('ccontainer').appendChild(clone);
i++;
}
http://jsfiddle.net/Theopt/xNfSd/
fixed. changed cdefault id to id0 and this java script:
var i = 2;
var c = 0;
function add() {
$xpto = 'gtitle'+i;
$xpto2 = 'gmessage'+i;
var klon = $( '#id'+ c );
klon.clone().attr('id', 'id'+(++c) ).insertAfter( '#inserthere' );
document.getElementById('id'+(c)).style.display = '' ;
$("#id"+(c)+" input[id='gtitle1']").attr('name', $xpto);
$("#id"+(c)+" textarea[id='gmessage1']").attr('name',$xpto2);
i++;
}

Can not add bullets for word using OpenXml

My expected result is:
Hello
world!
but when i using below codes:
MainDocumentPart mainDocumentPart =
package.AddMainDocumentPart();
DocumentFormat.OpenXml.Wordprocessing.Document elementW =
new DocumentFormat.OpenXml.Wordprocessing.Document(
new Body(
new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
new NumberingProperties(
new NumberingLevelReference() { Val = 0 },
new NumberingId() { Val = 1 })
),
new Run(
new RunProperties(),
new Text("Hello, ") { Space = new DocumentFormat.OpenXml.EnumValue<DocumentFormat.OpenXml.SpaceProcessingModeValues> { InnerText = "preserve" } })),
new DocumentFormat.OpenXml.Wordprocessing.Paragraph(
new ParagraphProperties(
new NumberingProperties(
new NumberingLevelReference() { Val = 0 },
new NumberingId() { Val = 1 })),
new Run(
new RunProperties(),
new Text("world!")
{
Space = new DocumentFormat.OpenXml.EnumValue<DocumentFormat.OpenXml.SpaceProcessingModeValues> { InnerText = "preserve" }
})));
elementW.Save(mainDocumentPart);
Result is:
Hello
world!
How can i get my expected result?
I realize this is far too late but maybe it can help others with the same question. The marked answer (by amurra) doesn't actually achieve the desired result. It simply creates a document with the list as content, just more completely than you. What you have added to the main document part is fine.
In the XML format, list items are defined as paragraphs with an indentation level and a numbering ID. This ID references the numbering rules defined in the NumberingDefinitionsPart of the document.
In your case, because you've set the numbering ID to be 1, the following code would map that ID of 1 to reflect a bulleted list as desired. Note the NumberingFormat and LevelText objects inside the Level object. These are the key components for your formatting.
NumberingDefinitionsPart numberingPart =
mainDocumentPart.AddNewPart<NumberingDefinitionsPart>("myCustomNumbering");
Numbering numElement = new Numbering(
new AbstractNum(
new Level(
new NumberingFormat() { Val = NumberFormatValues.Bullet },
new LevelText() { Val = "ยท" }
) { LevelIndex = 0 }
) { AbstractNumberId = 0 },
new NumberingInstance(
new AbstractNumId(){ Val = 0 }
){ NumberID = 1 }
);
numElement.Save(numberingPart);
For more information, check out the documentation for all the related classes on the Wordprocessing Namespace on MSDN, or the Working With Numbering markup article.
This should create you a blank document with your expected output:
// Creates an Document instance and adds its children.
public Document GenerateDocument()
{
Document document1 = new Document();
document1.AddNamespaceDeclaration("ve", "http://schemas.openxmlformats.org/markup-compatibility/2006");
document1.AddNamespaceDeclaration("o", "urn:schemas-microsoft-com:office:office");
document1.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
document1.AddNamespaceDeclaration("m", "http://schemas.openxmlformats.org/officeDocument/2006/math");
document1.AddNamespaceDeclaration("v", "urn:schemas-microsoft-com:vml");
document1.AddNamespaceDeclaration("wp", "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing");
document1.AddNamespaceDeclaration("w10", "urn:schemas-microsoft-com:office:word");
document1.AddNamespaceDeclaration("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
document1.AddNamespaceDeclaration("wne", "http://schemas.microsoft.com/office/word/2006/wordml");
Body body1 = new Body();
Paragraph paragraph1 = new Paragraph(){ RsidParagraphAddition = "00AF4948", RsidParagraphProperties = "00625634", RsidRunAdditionDefault = "00625634" };
ParagraphProperties paragraphProperties1 = new ParagraphProperties();
ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId(){ Val = "ListParagraph" };
NumberingProperties numberingProperties1 = new NumberingProperties();
NumberingLevelReference numberingLevelReference1 = new NumberingLevelReference(){ Val = 0 };
NumberingId numberingId1 = new NumberingId(){ Val = 1 };
numberingProperties1.Append(numberingLevelReference1);
numberingProperties1.Append(numberingId1);
paragraphProperties1.Append(paragraphStyleId1);
paragraphProperties1.Append(numberingProperties1);
Run run1 = new Run();
Text text1 = new Text();
text1.Text = "Hello";
run1.Append(text1);
paragraph1.Append(paragraphProperties1);
paragraph1.Append(run1);
Paragraph paragraph2 = new Paragraph(){ RsidParagraphAddition = "00625634", RsidParagraphProperties = "00625634", RsidRunAdditionDefault = "00625634" };
ParagraphProperties paragraphProperties2 = new ParagraphProperties();
ParagraphStyleId paragraphStyleId2 = new ParagraphStyleId(){ Val = "ListParagraph" };
NumberingProperties numberingProperties2 = new NumberingProperties();
NumberingLevelReference numberingLevelReference2 = new NumberingLevelReference(){ Val = 0 };
NumberingId numberingId2 = new NumberingId(){ Val = 1 };
numberingProperties2.Append(numberingLevelReference2);
numberingProperties2.Append(numberingId2);
paragraphProperties2.Append(paragraphStyleId2);
paragraphProperties2.Append(numberingProperties2);
Run run2 = new Run();
Text text2 = new Text();
text2.Text = "world!";
run2.Append(text2);
paragraph2.Append(paragraphProperties2);
paragraph2.Append(run2);
SectionProperties sectionProperties1 = new SectionProperties(){ RsidR = "00625634", RsidSect = "00AF4948" };
HeaderReference headerReference1 = new HeaderReference(){ Type = HeaderFooterValues.Even, Id = "rId7" };
HeaderReference headerReference2 = new HeaderReference(){ Type = HeaderFooterValues.Default, Id = "rId8" };
FooterReference footerReference1 = new FooterReference(){ Type = HeaderFooterValues.Even, Id = "rId9" };
FooterReference footerReference2 = new FooterReference(){ Type = HeaderFooterValues.Default, Id = "rId10" };
HeaderReference headerReference3 = new HeaderReference(){ Type = HeaderFooterValues.First, Id = "rId11" };
FooterReference footerReference3 = new FooterReference(){ Type = HeaderFooterValues.First, Id = "rId12" };
PageSize pageSize1 = new PageSize(){ Width = (UInt32Value)12240U, Height = (UInt32Value)15840U };
PageMargin pageMargin1 = new PageMargin(){ Top = 1440, Right = (UInt32Value)1440U, Bottom = 1440, Left = (UInt32Value)1440U, Header = (UInt32Value)720U, Footer = (UInt32Value)720U, Gutter = (UInt32Value)0U };
Columns columns1 = new Columns(){ Space = "720" };
DocGrid docGrid1 = new DocGrid(){ LinePitch = 360 };
sectionProperties1.Append(headerReference1);
sectionProperties1.Append(headerReference2);
sectionProperties1.Append(footerReference1);
sectionProperties1.Append(footerReference2);
sectionProperties1.Append(headerReference3);
sectionProperties1.Append(footerReference3);
sectionProperties1.Append(pageSize1);
sectionProperties1.Append(pageMargin1);
sectionProperties1.Append(columns1);
sectionProperties1.Append(docGrid1);
body1.Append(paragraph1);
body1.Append(paragraph2);
body1.Append(sectionProperties1);
document1.Append(body1);
return document1;
}

Return rows from stored procedure

I have this code:
public IEnumerable<SomeClass> GetAvalibleThingies(DateTime startDate, DateTime endDate, int categoryID)
{
if (_entities.Connection.State == System.Data.ConnectionState.Closed)
_entities.Connection.Open();
using (EntityCommand c = new EntityCommand("SomeEntities.GetAvalibleThingies", (EntityConnection)this._entities.Connection))
{
c.CommandType = System.Data.CommandType.StoredProcedure;
EntityParameter paramstartDate = new EntityParameter("startDate", System.Data.DbType.DateTime);
paramstartDate.Direction = System.Data.ParameterDirection.Input;
paramstartDate.Value = startDate;
c.Parameters.Add(paramstartDate);
........
var x = c.ExecuteReader();
return x as IEnumerable<SomeClass>;
};
But I can't get it to return a list of SomeClass. What's needed to do here? I use the entity framework 3.5sp1 one
/M
EntityDataReader is a class similar to SqlDataReader and should be handled in the similar way.
Instead of the lines
var x = c.ExecuteReader();
return x as IEnumerable;
should be something like
List list = new List();
using(EntityDataReader reader = c.ExecuteReader()) {
while(reader.Read()) {
SomeClass item = new SomeClass() {
};
list.Add(item);
}
}
return list;