Adding to list<objcect> with foreach loop - c#

Is it possible something like this? I've worked hard, but I think it's not possible, I hope someone will help me.
I have to fill the object like this,
var obj = new
{
parentObj = new List<object>()
{
outsideArray.ForEach(x=>
{
})
}
}
I dont like this.
var obj = new
{
parentObj= new List<object>()
{
new object() { bla, bla }
}
}
I want to do.
var obj {
Id =1,
Name= "any",
Address = new {
userAddressList.forEach(x=> {
Town = x.town,
State = x.state
}
}
}

The code in the second and third code snippets does not comply to C# syntax.
However, you may use LINQ to fill your array nicely similar to what shown in the third snippet:
var obj = new
{
Id = 1,
Name = "any",
Address = userAddressList.Select(x =>
{
Town = x.town,
State = x.state
})
};

Related

c# Nest and Elasticsearch Aggregations

Does anyone know how to do multiple aggregations with nest?
I have found quite a few examples unfortunately none of them work.
Here's what I have:
Vehicles fields = new Vehicles();
//create a terms query
var query = new TermsQuery
{
IsVerbatim = true,
Field = "VehicleOwnerId",
Terms = new string[] { 25 },
};
var aggregations = new Dictionary<string, IAggregationContainer>
{
{ "years", new AggregationContainer
{
Terms = new TermsAggregation(nameof(fields.Year))
{
Field = new Field(nameof(fields.Year))
}
}
}
//,
//{ "makes", new AggregationContainer
// {
// Terms = new TermsAggregation("Make")
// {
// Field = new Field(nameof(fields.Make))
// }
// }
//}
};
//create the search request
var searchRequest = new SearchRequest
{
Query = query,
From = 0,
Size = 100,
Aggregations = aggregations
};
var result = client.SearchAsync<InventoryLiveView>(searchRequest).Result;
var years = result.Aggregations.Terms("years");
Dictionary<string, long> yearCounts = new Dictionary<string, long>();
foreach (var item in years.Buckets)
{
yearCounts.Add(item.Key, item.DocCount ?? 0);
}
If I just execute the code like this it works. Years returns the aggregates as expected. If I try to add another field (like the one commented out above) it fails and I get zero records.
How can I get multiple aggregates in one query? I see examples of it all over, but none of the examples I've tried seem to work and most seem to be outdated (including some in the Nest documentation).
I have also tried this approach which is pretty close to the documentation.
//create the search request
var searchRequest = new SearchRequest
{
Query = query,
From = 0,
Size = 100,
//Aggregations = aggregations
Aggregations = new AggregationDictionary
{
{
"childAgg", new ChildrenAggregation("childAgg", typeof(Vehicles ))
{
Aggregations = new AggregationDictionary
{
{"years", new TermsAggregation(nameof(fields.VehicleYear))},
{"makes", new TermsAggregation(nameof(fields.VehicleMakeName))},
{"models", new TermsAggregation(nameof(fields.VehicleModelName))},
}
}
}
}
};
var result = client.SearchAsync<Vehicles>(searchRequest).Result;
This just produces a null reference exception.
I guess I'll never have too worry about getting to proud as a programmer :)
It's too often that the solution to the problem makes me feel stupid when it reveals itself.
So my issue was that the field I was trying to use in the aggregation was text and couldn't be used. I switched everything to the ID fields and multiple aggregations work as expected.
So this version of the code works like a champ:
Vehicle fields = new Vehicle ();
//create a terms query
var query = new TermsQuery
{
IsVerbatim = true,
Field = "VehicleOwnerId",
Terms = new string[] { "30" },
};
string[] Fields = new[]
{
nameof(fields.Year),
nameof(fields.MakeId),
nameof(fields.ModelId)
};
var aggregations = new Dictionary<string, IAggregationContainer>();
foreach (string sField in Fields)
{
var termsAggregation = new TermsAggregation(sField)
{
Field = sField
};
aggregations.Add(sField, new AggregationContainer { Terms = termsAggregation });
}
//create the search request
var searchRequest = new SearchRequest
{
Query = query,
From = 0,
Size = 10,
Aggregations = aggregations
};
var result = client.SearchAsync<InventoryLiveView>(searchRequest).Result;
var years = result.Aggregations.Terms(nameof(fields.Year));
Dictionary<string, long> yearCounts = new Dictionary<string, long>();
foreach (var item in years.Buckets)
{
yearCounts.Add(item.Key, item.DocCount ?? 0);
}
The exact error from elasticsearch, which I saw using postman was:
Fielddata is disabled on text fields by default. Set fielddata=true on [MakeName] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.
Here is my example using SearchDescriptors. My only problem is how to serialize returned results into a proper Key Value list. Is Looping through a fields list the best way to return results.
SearchDescriptor<Advert> agghDescriptor = new SearchDescriptor<Advert>();
agghDescriptor.Aggregations(ag => ag.Terms("make", a => a.Field(f => f.Make)) &&
ag.Terms("region", a => a.Field(f => f.Region)) &&
ag.Terms("city", a => a.Field(f => f.City)) &&
ag.Terms("category", a => a.Field(f => f.Category)) &&
ag.Terms("application", a => a.Field(f => f.Application)) &&
ag.Terms("portalId", a => a.Field(f => f.PortalId)) &&
ag.Terms("isActiveAuctionAdvert", a => a.Field(f => f.IsActiveAuctionAdvert)) &&
ag.Terms("isBargainAccount", a => a.Field(f => f.IsBargainAccount)) &&
ag.Terms("condition", a => a.Field(f => f.Condition))
);
agghDescriptor.Size(0);
var json2 = _client.RequestResponseSerializer.SerializeToString(agghDescriptor);
var aggregationResult = _client.Search<Advert>(agghDescriptor);
List<string> fields = new List<string>();
fields.Add("make");
fields.Add("category");
fields.Add("region");
List<Aggregation> aggregations = new List<Aggregation>();
foreach (var field in fields)
{
var aggrs = aggregationResult.Aggregations.Terms(field);
List<AggregateItem> aggregateItems = new List<AggregateItem>();
foreach (var item in aggrs.Buckets)
{
aggregateItems.Add(new AggregateItem()
{
Count = item.DocCount ?? 0,
Key = item.Key
});
}
aggregations.Add(new Aggregation()
{
Name = field,
Aggregates = aggregateItems
});
}

LINQ to handle IEnumerable and remove unmatch items from sub entity

I encountered a problem in my work recently, the following is the source code,
this.NameList = new ObservableCollection<Name>();
List<Others> others1 = new List<Others>();
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
List<Others> others2 = new List<Others>();
others2.Add(new Others() { Company = "Company2", School = "School2" });
others2.Add(new Others() { Company = "Company2", School = "School2" });
others2.Add(new Others() { Company = "Company2", School = "School2" });
List<Others> others3 = new List<Others>();
others3.Add(new Others() { Company = "Company3", School = "School3" });
others3.Add(new Others() { Company = "Company3", School = "School3" });
others3.Add(new Others() { Company = "Company3", School = "School3" });
this.NameList.Add(new Name() { FirstName = "Jacob", LastName = "Deng", Others = others1 });
this.NameList.Add(new Name() { FirstName = "David", LastName = "Xu", Others = others2 });
this.NameList.Add(new Name() { FirstName = "Helen", LastName = "Liu", Others = others3 });
please click here to see the output of above code
And then please read the following code,
List<Others> others1 = new List<Others>();
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
others1.Add(new Others() { Company = "Company1", School = "School1" });
List<Others> others2 = new List<Others>();
List<Others> others3 = new List<Others>();
this.NameList.Add(new Name() { FirstName = "Jacob", LastName = "Deng", Others = others1 });
this.NameList.Add(new Name() { FirstName = "David", LastName = "Xu", Others = others2 });
this.NameList.Add(new Name() { FirstName = "Helen", LastName = "Liu", Others = others3 });
Please click here for the output of the second snippet code
From above two snippets, you might notice that the second snippet doesn't contain any items in other2 and other3, you can easily understand from the preview output.
Now the question comes, how do we use LINQ to IEnumerable to handle such case, how to use LINQ to remove those items from Others entity? but we need to keep other2 and other3 not to be null (keep it count is 0). Besides LINQ, are there any other solutions?
I tried to use the following, but failed,
var others = ((MyVM)DataContext).NameList.Select(n => n.Others.Where(o => o.School == "School1")).ToList();
I just did some test, if we don't use LINQ, then we can use the following snippet code to fix my it.
ObservableCollection<Name> nameList = ((MyVM)DataContext).NameList;
foreach(Name n in nameList)
{
List<Others> removeList = new List<Others>();
for(int i=0;i<n.Others.Count;i++)
{
if(n.Others[i].School!="School1")
{
removeList.Add(n.Others[i]);
}
}
foreach(Others other in removeList)
{
n.Others.Remove(other);
}
}
But it looks very redundant, and we know that LINQ is very useful and i believed that it can be fixed with LINQ. Hope someone could help me to fix it with LINQ,thanks.
Appreciate if someone could help me. Thanks a lot.
It's better to use List<T>.RemoveAll in your case. See Using LINQ to remove elements from a List<T> for more details.
ObservableCollection<Name> nameList = ((MyVM)DataContext).NameList;
foreach(Name n in nameList)
{
n.Others.RemoveAll(s => s.School != "School1");
}
Linq is good at read-only iterating instead of updating/deleting. If you insist using Linq, you have to re-construct each item.
var newList = from nl in this.namelist
// this list can be empty but never null
let notSchool1 = (from s in nl.Others
where s.School != "School1"
select s).ToList()
select new Name
{
FirstName = nl.FirstName,
LastName = nl.LastName,
Others = noSchool1
};
this.NameList = new ObservableCollection<Name>(newList);
Above code may break other functionalities in your application, because these items are observed.
As I understand your question,
You want to remove others whose school value is not 'School1'. There are different way available for that but I recommend to filter the data from NameList which you want.
You can try below code to get others list with 'School1'
var result = NameList.Select(name => new Name()
{
FirstName = name.FirstName,
LastName = name.LastName,
Others = name.Others.Where(obj => obj.School == "School1").ToList()
}
).ToList();

ODataComplexValue Actions and Casting

So I'm new to OData and I'm using Simple.OData.Client
So my code first looked like this :
var context = new ODataClient("http://localhost:51861/API/");
var test = context.For<Account>()
.Key("00010017")
.Action("Testing")
.Set(new Entry() { { "MyTest", New Test() { Item = "Hello World"} } })
.ExecuteAsScalarAsync<Test>()
.Result;
Leads to the following error:
"The value for parameter 'MyTest' is of type 'ODataExample.Model.MyTest'. WriteValue can only write null, ODataComplexValue, ODataEnumValue and primitive types that are not Stream type."
Ok, cool, so the exception above is informative and I can work with this by doing
ODataComplexValue MyTest = new ODataComplexValue();
ODataProperty myP = new ODataProperty();
myP.Name = "Item";
myP.Value = "Hello World";
myCustomer.TypeName = "ODataExample.Model.MyTest";
myCustomer.Properties = new[] { myP };
So now if I pass myTest into the .Set I get a working call to my OData server
.Set(new Entry() { { "MyTest", MyTest )
So Obviously I can create a ODataComplexValue with something like
var tt = new ODataComplexValue()
{
TypeName = t.GetType().FullName,
Properties = s.GetType().GetProperties().Select<PropertyInfo,ODataProperty>(x => new ODataProperty { Name = x.Name, Value = x.GetValue(t) })
};
The above works great and I an just create an extension method from that to have
.Set(new Entry() { { "MyTest", New Test() { Item = "Hello World"} } }.ToOData())
However, I can't help but feel I'm missing something, if the solution is this simple, why is Simple.OData.Client not just doing this for me? Is is there already an extension method or utility I should be using to get the same above result.
Just incase its required my webapi routing is as followed :
var function = builder.EntityType<Account>().Action("Testing");
function.Namespace = "Transaction";
function.Parameter<Test>("MyTest");
function.ReturnsFromEntitySet<Test>("Test");

RavenDB Collection "in" Collection query

I need to preform a query that check if a collection is in given collection, just like the regular in operation but for collections.
class Post
{
public string[] Tags {get;set;}
}
session.Queury<Post>.Where(x=>x.Tags.in(new[]{".net","c#","RavenDB"})).ToList();
so if i have in my DB:
new Post{Tags= new[]{"C#",".net"}};
it will be returned
but if i have:
new Post{Tags= new[]{"C#",".net","SQLServer"}};
it will not be returned.
Update:
what i am trying to do is this:
session.Query<Post>()
.Where(x => x.Tags.All(y => y.In(new[] { "C#", ".net", "RavenDB" })))
.ToList();
but i got System.NotSupportedException.
I manage to find a solution:
static void Main(string[] args)
{
var sessionStore = new EmbeddableDocumentStore
{
RunInMemory = true,
UseEmbeddedHttpServer = true,
Conventions =
{
DefaultQueryingConsistency = ConsistencyOptions.AlwaysWaitForNonStaleResultsAsOfLastWrite
}
};
sessionStore.Initialize();
using (var session = sessionStore.OpenSession())
{
var allTags = new[] {"C#", ".net", "RavenDB", "Linux", "Mac"};
var tagsCollection = new[] {"C#", ".net", "RavenDB"};
var complementTagsCollection = allTags.Except(tagsCollection).ToList();
session.Store(new Post
{
Tags = new List<string>{"C#",".net"}
});
session.SaveChanges();
// Posts where all their tags are in tagsCollection
var result = session.Query<Post>().Where(x => !x.Tags.In(complementTagsCollection)).ToList();
}
}
The way IN works, it matches ANY of them.
If you want to match all you have to do a separate check for each.

Searching item in List

person[] prn =
new person[]
{
new person { Name = "Robert", RList =
{new ReceipeList { NameofRecipie = "Coak" },
new ReceipeList { NameofRecipie = "Pizza" } } },
new person { Name = "Rahim", RList =
{ new ReceipeList { NameofRecipie = "Coak" },
new ReceipeList { NameofRecipie = "OnionBread" }} },
};
When searching an item
ReceipeList lstr = new ReceipeList();
lstr.NameofRecipie = "Coak";
using
var query = from lst in prn where(lst.RList.Contains(lstr) ) select lst;
it did not return any result.
foreach (var v in query)
{
Console.Write(v.Name.ToString()+" ordered :");
foreach(ReceipeList lst in v.RList)
{
Console.Write(lst.NameofRecipie.ToString()+",");
}
Console.WriteLine();
}
This isn't working because you're searching for a specific instance of ReceipeList (by reference). Because of this, your query will only return values that have your specific lstr instance of ReceipeList, not a ReceipeList with the same value as the one you're specifying.
You could make this work by overriding Equals in ReceipeList, or by reworking your query to:
string lstr = "Coak";
var query = from lst in prn
where lst.RList.Any(r => r.NameofRecipie == lstr)
select lst;
This works because it uses the Any() method to search the ReceipeList instances by a predicate, instead of searching for a specific instance.
Im Not sure if, but you can look at this also, might help a little bit?

Categories