Universal app object distinct by variable - c#

I have a problem:
In my code I have this obj
//:extension for being saved locally
public class FOO
{
public int ID { get; set; }
public string STRINGVALUE{ get; set; }
public int INTVALUE { get; set; }
//ecc..
//SelectAll() method which returns all FOO in local DB
}
Now what I want is, in some cases, to pick all FOO obj where STRINGVALUE (or INTVALUE) is not duplicated.
For example:
List<FOO> fooes = new FOO().SelectAll();
List<FOO> uniqueIntFoo = fooes.distinct(); //here i have to set the clause
There is the Distinct() method in Linq, but it compare the entire item, not a single variable of it.
Any of you know how can I do it?

What about grouping the results, something like:
By both Int and StrValue:
var uniqueItems = fooes.GroupBy(x => new{x.IntVal, x.StrVal});
By IntVal:
var uniqueItems = fooes.GroupBy(x => x.IntVal);
Edit, as suggested by question's author:
fooes.GroupBy(x => x.INTVALUE).Select(y => y.First()).Distinct().ToList();

Related

MongoDB.net driver - project into different class

When trying to project a typed document into a different class, I get the following: Could not find a member match for constructor parameter "origItem" on type "NewItem" in the expression tree new NewItem({document}, 1021).
A simplified example of the classes are as follows:
public class OriginalItem
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public IList<double> Data { get; set; }
public OriginalItem() { }
}
public class NewItem
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public double Value { get; set; }
public NewItem() { }
public NewItem( OriginalItem origItem, int targetIdx )
{
Id = origItem.Id;
Name = origItem.Name;
Value = origItem.Data[targetIdx];
}
}
An example of where the issue occurs is as follows:
IList<ObjectId> ids; // list of OriginalItem Ids to get
IMongoCollection<OriginalItem> collection = _db.GetCollection<OriginalItem>("items");
int targetIdx = 50;
IList<NewItem> newItems = await collection.Aggregate()
.Match( item => ids.Contains( item.Id ) )
.Project( origItem => new NewItem( origItem, targetIdx ) )
.ToListAsync();
I looked around and it seems like my only option would be project & transform the the origItem into a BsonDocument, and deserialize that into a NewItem. I've also tested changing new NewItem( origItem, targetIdx ) to new NewItem { //... } works.
I know I can simply read the item and perform the necessary transformations outside of the mongo server, but the real use case is slightly more complicated and I would like to at least figure out what I'm failing to understand.
Thank you
I have run into this issue as well. After scouring the internet for a while, I finally found that using the Builder's Project.Expression method was the only way that worked. For your scenario it would result in something like the following
var project = Builders<OriginalItem>.Projection.Expression(item => new NewItem(origItem, targetInx));
IList<NewItem> newItems = await collection.Aggregate()
.Match( item => ids.Contains( item.Id ) )
.Project(project)
.ToListAsync();
I also removed all of the constructor logic, and instead had it doing straight assignments. So instead of
new NewItem(origItem, targetInx) you would end up with something like new NewItem(item.Id, item.Name, item.Data[targetIdx]). I'm not certain if this step is necessary, but if the above doesn't work then I would definitely try this as well.

Linq query a List of objects containing a list of object

I have a list of foo called crepes. I want to return foo where bar.doritos == "coolRanch"
class foo
{
List<bar> item;
string candy;
string beer;
}
class bar
{
string doritos;
string usb;
}
var item = crepes.item.Where(x => x.doritos == "coolRanch").FirstOrDefault();
From other threads, i've pieced together the above linq query, but crepes.item throws an error. "List does not contain a definition for 'item' and no definition for 'item' accepting first argument...
Given that crepes is a List<Foo>, you need to add an additional level to the linq query.
var item = crepes.Where(a => a.item.Any(x => x.doritos == "coolRanch")).FirstOrDefault();
Your item access modifier is private (this is C# default for class), it should be made public
This goes for your doritos too
Also, since your crepes is a List, put additional layer of LINQ (as also suggested by others) to completely fix it, something like this
var item = crepes.Where(f => f.item.Any(b => b.doritos == "coolRanch")).FirstOrDefault(); //f is of foo type, b is of bar type
If you fix your classes like this
class Foo
{
public List<Bar> Items { get; set; }
public string Candy { get; set; }
public string Beer { get; set; }
}
class Bar
{
public string Doritos { get; set; }
public string Usb { get; set; }
}
Your query will look like
var crepes = new List<Foo>();
var item = crepes.FirstOrDefault(f => f.Items.Any(b => b.Doritos == "coolRanch"));
Here, we are trying to get the first Foo which has at least one Bar in Items where Doritos == "coolRanch".

Dapper: Not able to parse string from dbf(Error parsing column)

I want to use dapper to query over dbf files. In my file example.dbf I have two columns:
Value - type NUMERIC
Name - type CHARACTER
I write class ExampleDbf
class ExampleDbf
{
public int Value { get; set; }
public string Name { get; set; }
}
Now I want to write two simple query
var listOne = connection.Query<ExampleDbf>("SELECT value FROM Example");
var listTwo = connection.Query<ExampleDbf>("SELECT name, value FROM Example");
ListOne are OK but when I execute listTwo I Have following System.Data.DataException:
Additional information: Error parsing column 0 (name=System.Byte[] - Object)
When I use standard DataReader I must write something like that
example.name = System.Text.Encoding.ASCII.GetString((byte[])reader["name"]).Trim();
Of course I may write something like this:
class ExampleDbf2
{
public int Value { get; set; }
public byte[] Name { get; set; }
public string StringName
{
get
{
return System.Text.Encoding.ASCII.GetString((byte[])Name ).Trim();
}
}
}
So now it works
var listTwo = connection.Query<ExampleDbf2>("SELECT name, value FROM Example");
But this solution is very ugly, maybe someone have better solution.
You could always return a dynamic, then map it to your object and perform the transformation operation during object initialization.
var listTwo = connection.Query<dynamic>("SELECT name, value FROM Example")
.Select(x => new ExampleDbf
{
Value = x.value,
Name = System.Text.Encoding.ASCII.GetString((byte[])x.name).Trim()
}).ToList();

C# Find and edit single object on list

public class kDrinki
{
public int id {get; set;}
public string nazwa { get; set; }
public string skladniki { get; set; }
public string opis { get; set; }
public string sciezka { get; set; }
public kDrinki(int _id, string _nazwa, string _skladniki, string _opis, string _sciezka)
{
id = _id;
nazwa = _nazwa;
skladniki = _skladniki;
opis = _opis;
sciezka = _sciezka;
}
}
I have got that class. I created List lst_pDrinkow of object and added some form XML. I don't know how to find only single object (using object id not list id) from list and edit all his data(not only single parameter).
You could try something like this:
var obj = lst_pDrinkow.SingleOrDefault(x=>x.id==Id);
Where Id is the id of the object you are looking for.
If there is an object with the supplied Id, you will get it. Otherwise, the result would be null.
Once you get the object you want, it's very easy to update it's data.
if(obj!=null)
{
obj.nazwa = "new value";
// update the values of the other properties with the same way.
}
Update
While it is not your case, I have to note here that if there are more than one objects with the supplied Id, then you will get an exception. We usually use the SingleOrDefault, when we are sure that the object we are looking for it is unique if at all exists.
More formally:
Returns the only element of a sequence, or a default value if the
sequence is empty; this method throws an exception if there is more
than one element in the sequence.
as it is stated here.
List<kDrinki> items = new List<kDrinki>();
var tmp1 = items.SingleOrDefault(a => a.id == 10);
tmp1.skladniki = "new value";
var tmp2 = items.SingleOrDefault(a => a.opis.Contains("some strings"));
tmp2.skladniki = "new value2";

C# LINQ subquery (On entities)

I am trying to use LINQ to query a list of objects wherever appropriate. Currently I am stuck on the syntax of a nested query which I hope you can help me with.
Classes:
public class FooType
{
public int Id { get; set; }
public IList<Foo> Foos { get; set; }
}
public class Foo
{
public int FooTypeId { get; set; }
public string CorrelationId { get; set; }
}
public class Bar
{
public string FooCorrelationId { get; set; }
}
Usage:
IList < FooType > fooTypes = new List < FooType >();
// ... add a lot of FooTypes, each enriched with some Foos
Bar bar = new Bar(){FooCorrelationId = "abcdef"};
Foo foo = fooTypes.Where( ft => ft.Foos.Where( f => f.CorrelationId == bar.FooCorrelationId ) ).First<Foo>();
This fails because the outer WHERE-expression is fed with something that does not provide a boolean return value. As you might guess, I intend to something like the following in LINQ:
foreach (FooType fooType in fooTypes)
{
Foo foo = fooType.Foos
.Where(f => f.CorrelationId == bar.FooCorrelationId)
.First();
}
Do you have any idea how to get that Foo I'm looking for, the one with CorrelationId "abcdef"?
And one more question for the benchmarkers : What about performance? Does LINQ optimize it's queries? Or is the result the same as an iteration over the objects like I did in my "something like" block?
Thanks a lot in advance!
Just replace the outer where with a SelectMany and get the first
Foo foo = fooTypes
.SelectMany(ft => ft.Foos.Where(f => f.CorrelationId == bar.FooCorrelationId))
.First();
If you an to get the first Foo across all FooType, what has CorrelationId == FooCorrelationId.

Categories

Resources