I have PHP code
$records = array(
array('myobjecttype' => array('field1' => 'value', 'field2' => 'value')),
array('myotherobjecttype' => array('field1' => 'value', 'field2' => 'value'))
);
I am working on converting php code to C#. Above php code is used later to loop through and create xml where each array is Node in xml.
I need similar data structure in c# which can do the same task. Kindly guide me.
Pavan
Why not create a proper class with properties and create a list of them?
public class Record
{
public string Field1{get;set;}
public string Field2{get;set;}
}
And then in your method you do the following:
var recordA = new Record{Field1 = "Value 1", Field2 = "Value 2"};
var recordB = new Record{Field1 = "Value 1", Field2 = "Value 2"};
var records = new List<Record>{recordA, recordB};
UPDATE
You obviously want to define the Record properties with a proper names like Title, ReleaseDate etc. and give them types like int, DateTime etc.
Related
I was wandering how to output (or format) data in LinqPad as a table. I know that for some data types LinqPad generates tables. For example, it can dump 2D-arrays:
After googling, I didn't find a direct answer. Let's say I want to create a two-columns table for DateOnly.ToString(...):
format string
formatted value
toString()
27/12/2022
ToString(DD.MM.YYYY)
DD.12.YYYY
ToString(dd.MM.yyyy)
27.12.2022
How can I build such a table in LinqPad?
It seems like the correct solution is to use a collection of anonymous types to build tables.
The following code:
DateOnly dateOnlyNow = DateOnly.FromDateTime(DateTime.Now);
var output = new[] {
new { method = "ToString()", value = dateOnlyNow.ToString() },
new { method = "ToString(DD.MM.YYYY)", value = dateOnlyNow.ToString("DD.MM.YYYY") },
new { method = "ToString(dd.MM.yyyy)", value = dateOnlyNow.ToString("dd.MM.yyyy") },
};
output.Dump();
produces the expected result:
I want to convert a DataTable with 10 rows or more into an Array like this:
SqlConfiguration clist2 = new SqlConfiguration();
clist2.QueryString = "SELECT caption_id,caption,description FROM sws_template_detail WHERE template_id = 1";
DataTable db = clist2.GetRecords;
ListItem datalist = new ListItem();
foreach(DataRow row in db.Rows)
{
datalist = new ListItem
{
id = row["caption_id"].ToString(),
title = row["caption"].ToString(),
description = row["description"].ToString()
};
}
var section = new Section
{
title = "Title",
items = new ListItem[]
{
datalist
}
};
But the resulting data is only 1 row, how can I solve it?
You can do it in 1 line (well, 1 statement):
var section = new Section
{
title = "Title",
items = dataTable.Rows
.Cast<DataRow>()
.Select( row => new ListItem()
{
id = row["caption_id" ].ToString(),
title = row["caption" ].ToString(),
description = row["description"].ToString()
} )
.ToArray()
};
Though there's a lot of code smells going on here...
Why is an class named SqlConfiguration being used to execute a SQL query via a property named QueryString.
Public members in C#/.NET should be PascalCase not camelCase.
So it should be Section.Title, Section.Items, ListItem.Id, ListItem.Title, and ListItem.Description.
Don't use object-initializers for required members of an object, because there's no compile-time guarantees that they'll be populated.
If a ListItem must have an Id, Title, and Description then they should be passed-in as constructor parameters.
Using array-types (like ListItem[]) is usually not a good idea because array-types have the worst set of attributes in comparison to others: they're fixed-size but also mutable.
Whereas usually you want something resizable-and-mutable (e.g. List<T>) or completely immutable (e.g. ImmutableArray<T> or at least IReadOnlyList<T>).
Mutable elements
Resizable
Variance
T[] (Array types )
Yes
No
Unsafe
List<T>
Yes
Yes
Invariant
ImmutableArray<T>
No
No
Invariant
IReadOnlyList<T>
No
No
Covariant safe
try this
var items_array=new List<ListItem>();
foreach(DataRow row in db.Rows)
{
items_array.add(new ListItem
{
id = row["caption_id"].ToString(),
title = row["caption"].ToString(),
description = row["description"].ToString()
});
}
var section = new Section
{
title = "Title",
items = items_array.toArray()
};
Loading the data into a DataTable and then converting it into a List wastes both CPU and RAM. You can use an ORM like EF Core or Dapper to execute a query and return the results in the shape you want. For example, using Dapper, what you want is a single line:
var sql=#"select caption_id as Id, caption as Title, description
FROM sws_template_detail
WHERE template_id = 1";
var items=connection.Query<ListItem>(sql).ToArray();
Query<T> returns the results as an IEnumerable<T>. This is converted to an array using ToArray().
Dapper allows you to easily write parameterized queries instead of concatenating strings to construct a query:
var sql=#"select caption_id as Id, caption as Title, description
FROM sws_template_detail
WHERE template_id = #id";
var items=connection.Query<ListItem>(sql,new {id=1}).ToArray();
The query can be executed asynchronously using QueryAsync;
var items=(await connection.QueryAsync<ListItem>(sql,new {id=1}))
.ToArray();
I'm using C#, EF5, and Lambda style queries against SQL.
I have the usual scenario of binding data to gridviews. Some of the results for my columns may be too long (character count) and so I only want to display the first 'n' characters. Let's say 10 characters for this example. When I truncate a result, I'd like to indicate this by appending "...". So, let's say the following last names are returned:
Mercer, Smith, Garcia-Jones
I'd like them to be returned like this:
Mercer, Smith, Garcia-Jon...
I was doing something like this:
using (var context = new iaiEntityConnection())
{
var query = context.applications.Where(c => c.id == applicationPrimaryKey);
var results = query.ToList();
foreach (var row in results)
{
if (row.employerName.Length > 10)
{
row.employerName = row.employerName.Substring(0, Math.Min(10, row.employerName.ToString().Length)) + "...";
}
if (row.jobTitle.Length > 10)
{
row.jobTitle = row.jobTitle.Substring(0, Math.Min(10, row.jobTitle.ToString().Length)) + "...";
}
}
gdvWorkHistory.DataSource = results;
gdvWorkHistory.DataBind();
However, if I change my query to select specific columns like this:
var query2 = context.applications.Select(c => new
{
c.id,
c.applicationCode,
c.applicationCategoryLong,
c.applicationType,
c.renew_certification.PGI_nameLast,
c.renew_certification.PGI_nameFirst,
c.renew_certification.PAI_homeCity,
c.renew_certification.PAI_homeState,
c.reviewStatusUser,
c.dateTimeSubmittedByUser
})
The result appears to become read-only if specific columns are selected, and I really should be selecting just the columns I need. I'm losing my ability to edit the result set.
So, I'm rethinking the entire approach. There must be away to select the first 'n' characters on select, right? Is there anyway to append the "..." if the length is > 10 on select? That seems trickier. Also, I guess I could parse through the gridview after bind and make this adjustment. Or, perhaps there is a way to maintain my ability to edit the result set when selecting specific columns?
I welcome your thoughts. Thanks!
To quote MSDN
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first.
So you would have to define a class and select into that if you want read write capability.
e.g.
public class MyClass {
public int id { get; set; }
public string applicationCode {get; set; }
// rest of property defintions.
}
var query2 = context.applications.Select(c => new MyClass {
id = c.id,
applicationCode = c.applicationCode,
// Rest of assignments
};
As to just providing 10 character limit with ... appended. I'm going to assume you mean on the applicationcategoryLog field but you can use the same logic on other fields.
var query2 = context.applications.Select(c => new
{
c.id,
c.applicationCode,
applicationCategoryLong = (c.applicationCategoryLong ?? string.Empty).Length <= 10 ?
c.applicationCategoryLong :
c.applicationCategoryLong.Substring(0,10) + "...",
c.applicationType,
c.renew_certification.PGI_nameLast,
c.renew_certification.PGI_nameFirst,
c.renew_certification.PAI_homeCity,
c.renew_certification.PAI_homeState,
c.reviewStatusUser,
c.dateTimeSubmittedByUser
})
I´m trying to make a query in ElasticSearch with the NEST c# client a query without accent, my data has portuguese latin word with accent. See the code bellow:
var result = client.Search<Book>(s => s
.From(0)
.Size(20)
.Fields(f => f.Title)
.FacetTerm(f => f.OnField(of => of.Genre))
.Query(q => q.QueryString(qs => qs.Query("sao")))
);
This search did not find anything. My data on this index contains many titles like: "São Cristóvan", "São Gonçalo".
var settings = new IndexSettings();
settings.NumberOfReplicas = 1;
settings.NumberOfShards = 5;
settings.Analysis.Analyzers.Add("snowball", new Nest.SnowballAnalyzer { Language = "Portuguese" });
var idx5 = client.CreateIndex("idx5", settings);
How I can make query "sao" and find "são" using ElasticSearch?
I think have to create index with right properties, but I already tried many settings like.
or in Raw Mode:
{
"idx" : {
"settings" : {
"index.analysis.filter.jus_stemmer.name" : "brazilian",
"index.analysis.filter.jus_stop._lang_" : "brazilian"
}
}
}
How can I make the search and ignore accents?
Thanks Friends,
See the solution:
Connect on elasticsearch search with putty execute:
curl -XPOST 'localhost:9200/idx30/_close'
curl -XPUT 'localhost:9200/idx30/_settings' -d '{
"index.analysis.analyzer.default.filter.0": "standard",
"index.analysis.analyzer.default.tokenizer": "standard",
"index.analysis.analyzer.default.filter.1": "lowercase",
"index.analysis.analyzer.default.filter.2": "stop",
"index.analysis.analyzer.default.filter.3": "asciifolding",
"index.number_of_replicas": "1"
}'
curl -XPOST 'localhost:9200/idx30/_open'
Replace "idx30" with name of your index
Done!
I stumbled upon this thread since I got the same problem.
Here's the NEST code to create an index with an AsciiFolding Analyzer:
// Create the Client
string indexName = "testindex";
var uri = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(uri).SetDefaultIndex(indexName);
var client = new ElasticClient(settings);
// Create new Index Settings
IndexSettings set = new IndexSettings();
// Create a Custom Analyzer ...
var an = new CustomAnalyzer();
// ... based on the standard Tokenizer
an.Tokenizer = "standard";
// ... with Filters from the StandardAnalyzer
an.Filter = new List<string>();
an.Filter.Add("standard");
an.Filter.Add("lowercase");
an.Filter.Add("stop");
// ... just adding the additional AsciiFoldingFilter at the end
an.Filter.Add("asciifolding");
// Add the Analyzer with a name
set.Analysis.Analyzers.Add("nospecialchars", an);
// Create the Index
client.CreateIndex(indexName, set);
Now you can Map your Entity to this index (it's important to do this after you created the Index)
client.MapFromAttributes<TestEntity>();
And here's how such an entity could look like:
[ElasticType(Name = "TestEntity", DisableAllField = true)]
public class TestEntity
{
public TestEntity(int id, string desc)
{
ID = id;
Description = desc;
}
public int ID { get; set; }
[ElasticProperty(Analyzer = "nospecialchars")]
public string Description { get; set; }
}
There you go, the Description-Field is now inserted into the index without accents.
You can test this if you check the Mapping of your index:
http://localhost:9200/testindex/_mapping
Which then should look something like:
{
testindex: {
TestEntity: {
_all: {
enabled: false
},
properties: {
description: {
type: "string",
analyzer: "nospecialchars"
},
iD: {
type: "integer"
}
}
}
}
}
Hope this will help someone.
You'll want to incorporate an ACSII Folding filter into your analyzer to accomplish this. That will mean constructing the snowballanalyzer form tokenizers and filters (unless nest allows you to add filters to non-custom analyzers. ElasticSearch doesn't, though, as far as I know).
A SnowballAnalyzer incorporates:
StandardTokenizer
StandardFilter
(Add the ASCIIFolding Filter here)
LowercaseFilter
StopFilter (with the appropriate stopword set)
SnowballFilter (with the appropriate language)
(Or maybe here)
I would probably try to add the ASCIIFoldingFilter just before LowercaseFilter, although it might be better to add it as the very las step (after SnowballFilter). Try it both ways, see which works better. I don't know enough about either the Protuguese stemmer to say which would be best for sure.
I got an XML that I'm trying to parse using LINQ to XML and convert it to an anonymous list of objects. To do so, I come up with the following code snippet:
var res = doc
.Root
.Elements("Record")
.Elements("Term")
.Select(term => new
{
LanguageCode = term.Attribute("languageCode").Value,
ConceptNumber = Convert.ToInt32(term.Attribute("conceptNumber").Value),
IsHidden = Convert.ToBoolean(term.Attribute("hidden").Value),
Label = term.Value,
InputDate = DateTime.Parse(term.Parent.Element("InputDate").Value),
LastUpdate = DateTime.Parse(term.Parent.Element("LastUpdated").Value)
}).ToList();
Please pay attention to the InputDate & LastUpdate section. As you see, I've to access the parent node (say, term.Parent) so that I can access those 2 elements and this looks messy to me. Is there any way to declare term.Parent once and using it over and over again to extract those properties?
Here's an excerpt of the XML I'm trying to read:
<Record>
<Term languageCode="Prs" conceptNumber="10" hidden="False">Whatever</Term>
<Status>Approved</Status>
<Frequency>0</Frequency>
<InputDate>12/30/1899</InputDate>
<LastUpdate>10/25/2009</LastUpdate>
</Record>
Thank you
You need to use let clause. It creates a new variable inside query and allows to use it multiply times.
In your case it would be
var res = (from term in doc.Root.Elements("Record").Elements("Term")
let parent = term.Parent
select new
{
LanguageCode = term.Attribute("languageCode").Value,
ConceptNumber = Convert.ToInt32(term.Attribute("conceptNumber").Value),
IsHidden = Convert.ToBoolean(term.Attribute("hidden").Value),
Label = term.Value,
InputDate = parent.Element("InputDate").Value,
LastUpdate = parent.Element("LastUpdated").Value
}).ToList();
Note that its a code on a pure LINQ syntax that allow you to express ideas much clearer than using extension methods like in your question.
You can introduce an anonymous class in a projection (This is similar to what let does under the hood) and then use SelectMany() to flatten using the extra properties:
var results = doc.Elements("Record")
.Select( x => new
{
Terms = x.Elements("Term"),
InputDate = DateTime.Parse(x.Element("InputDate").Value),
LastUpdate = DateTime.Parse(x.Element("LastUpdate").Value)
})
.SelectMany(x => x.Terms, (record,term) => new
{
LanguageCode = term.Attribute("languageCode").Value,
..
InputDate = record.InputDate,
LastUpdate = record.LastUpdate
});