"select" query using "PetaPoco" ORM - c#

I tried something like the following, but it didn't work.
var _records = new string[] {"SqlServer", "IIS" };
var result = db.Fetch<EntityRecords>(#" select * from tblRecords where RecordName IN rs", new { rs = _records });
and also i have tried another way like the following, but same problem
var _records = new string[] {"SqlServer", "IIS" };
var query = PetaPoco.Sql.Builder.Select("*").From("tblRecords").Where("RecordName IN (#rs)",new { rs = _records });
var result = db.Query<EntityRecords>(query);

The first one should be
var result = db.Fetch<EntityRecords>(#" select * from tblRecords where RecordName IN (#rs)", new { rs = _records });
or
var result = db.Fetch<EntityRecords>(#" select * from tblRecords where RecordName IN (#0)", _records);
The second one I'm not too sure about because the following tests pass
[Fact]
public void Append_GivenArrayAndValue_ShouldBeValid()
{
// Simple collection parameter expansion
_sql = Sql.Builder.Append("#0 IN (#1) #2", 20, new int[] { 1, 2, 3 }, 30);
_sql.SQL.ShouldBe("#0 IN (#1,#2,#3) #4");
_sql.Arguments.Length.ShouldBe(5);
_sql.Arguments[0].ShouldBe(20);
_sql.Arguments[1].ShouldBe(1);
_sql.Arguments[2].ShouldBe(2);
_sql.Arguments[3].ShouldBe(3);
_sql.Arguments[4].ShouldBe(30);
}
[Fact]
public void Append_GivenArrayAndNamedValue_ShouldBeValid1()
{
// Simple collection parameter expansion
_sql = Sql.Builder.Append("#p1 IN (#p2) #p3", new { p1 = 20 }, new { p2 = new int[] { 1, 2, 3 }}, new { p3 = 30 });
_sql.SQL.ShouldBe("#0 IN (#1,#2,#3) #4");
_sql.Arguments.Length.ShouldBe(5);
_sql.Arguments[0].ShouldBe(20);
_sql.Arguments[1].ShouldBe(1);
_sql.Arguments[2].ShouldBe(2);
_sql.Arguments[3].ShouldBe(3);
_sql.Arguments[4].ShouldBe(30);
}

Related

Grouping and summing by Linq

I would like to get the total order amount for each customer with Linq, I know I need to group and sum I have only succeeded to group without summing the whole amount for each order.
var OrderByCustumer = new[] {
new { name = "cust1", order = 400 },
new { name = "cust1", order = 250 },
new { name = "cust1", order = 130 },
new { name = "cust2", order = 30 },
new { name = "cust3", order = 205}
};
var res= OrderByCustumer.GroupBy(x=>x.name).Select((x,y)=>new{
a=x.Key
});
foreach(var a in res){
Console.WriteLine(a);
}
.**
OutPut
a = cust1
a = cust2
a = cust3
**
Try this
var res = OrderByCustumer.GroupBy(x => x.name).Select(x => new {
a = x.Key,
sum = x.Sum(c => c.order)
});
foreach (var item in res)
{
Console.WriteLine($"{ item.a} - Sum = {item.sum}");
}

Change big collection into unique List of collections

I have a big list of objects and in this object there is a category ID something like:
var list = new List<Example>
{
new Example {CatId = 1, Value = new { }},
new Example {CatId = 1, Value = new { }},
new Example {CatId = 1, Value = new { }},
new Example {CatId = 2, Value = new { }},
new Example {CatId = 2, Value = new { }},
new Example {CatId = 3, Value = new { }}
// and so on
};
So I am looking for making this complicated list more organized like list of lists of unique elements
something like:
var result = new List<List<Example>>
{
new List<Example>
{
new Example {CatId = 1, Value = new { }},
new Example {CatId = 2, Value = new { }},
new Example {CatId = 3, Value = new { }}
},
new List<Example>
{
new Example {CatId = 1, Value = new { }},
new Example {CatId = 2, Value = new { }}
},
new List<Example>
{
new Example {CatId = 1, Value = new { }}
}
}
Problem is I do not what to use, group by will not fix my case, so how to do this in most efficient way.
So this is about partitioning, it's the sort of thing that is easy to do in a database query, but in c# you need to create some key with a partition number that you can then use to .GroupBy.
The partitioning itself is a grouping
var projected = list.GroupBy(x => x.CatId)
.SelectMany( g => g.Select( ( x, i ) => new { Item = x, rn = i + 1 } ) );
This gives you records that look like:
{"Item":{"CatId":1,"Value":{}},"rn":1}
{"Item":{"CatId":1,"Value":{}},"rn":2}
{"Item":{"CatId":1,"Value":{}},"rn":3}
{"Item":{"CatId":2,"Value":{}},"rn":1}
{"Item":{"CatId":2,"Value":{}},"rn":2}
{"Item":{"CatId":3,"Value":{}},"rn":1}
As you can see that rn ("row number") value can be used to group by:
var result = projected.GroupBy(x => x.rn, x => x.Item);
This gives us:
[{"CatId":1,"Value":{}},{"CatId":2,"Value":{}},{"CatId":3,"Value":{}}]
[{"CatId":1,"Value":{}},{"CatId":2,"Value":{}}]
[{"CatId":1,"Value":{}}]
So, all in 1 go:
var result = list.GroupBy(x => x.CatId)
.SelectMany( g => g.Select( ( x, i ) => new { Item = x, rn = i + 1 } ) )
.GroupBy(x => x.rn, x => x.Item);
Live example: https://dotnetfiddle.net/AlTfk8

Cartesian Product of an arbitrary number of objects [duplicate]

This question already has answers here:
Is there a good LINQ way to do a cartesian product?
(3 answers)
Closed 4 years ago.
I'm looking to get the Cartesian Product of an arbitrary number of objects in c#. My situation is slightly unusual - my inputs are not lists of base types, but objects which have a property that's a list of base types.
My input and output objects are as follows:
public class Input
{
public string Label;
public List<int> Ids;
}
public class Result
{
public string Label;
public int Id;
}
Some sample input data:
var inputs = new List<Input>
{
new Input { Label = "List1", Ids = new List<int>{ 1, 2 } },
new Input { Label = "List2", Ids = new List<int>{ 2, 3 } },
new Input { Label = "List3", Ids = new List<int>{ 4 } }
};
And my expected output object:
var expectedResult = new List<List<Result>>
{
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 1},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 2},
new Result{Label = "List3", Id = 4}
},
new List<Result>
{
new Result{Label = "List1", Id = 2},
new Result{Label = "List2", Id = 3},
new Result{Label = "List3", Id = 4}
}
};
If I knew the number of items in 'inputs' in advance I could do this:
var knownInputResult =
from id1 in inputs[0].Ids
from id2 in inputs[1].Ids
from id3 in inputs[2].Ids
select
new List<Result>
{
new Result { Id = id1, Label = inputs[0].Label },
new Result { Id = id2, Label = inputs[1].Label },
new Result { Id = id3, Label = inputs[2].Label },
};
I'm struggling to adapt this to an arbitrary number of inputs - is there a possible way to do this?
I consider this duplicate of question linked in comments, but since it was reopened and you struggle to adapt that question to your case, here is how.
First grab function by Eric Lippert from duplicate question as is (how it works is explained there):
public static class Extensions {
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item })
);
}
}
Then flatten your input. Basically just attach corresponding label to each id:
var flatten = inputs.Select(c => c.Ids.Select(r => new Result {Label = c.Label, Id = r}));
Then run cartesian product and done:
// your expected result
var result = flatten.CartesianProduct().Select(r => r.ToList()).ToList();
I'm not proud of the amount of time I spent messing with this, but it works.
It's basically black magic, and I would replace it the first chance you get.
public static List<List<Result>> Permutate(IEnumerable<Input> inputs)
{
List<List<Result>> results = new List<List<Result>>();
var size = inputs.Select(inp => factorial_WhileLoop(inp.Ids.Count)).Aggregate((item, carry) => item + carry) - 1;
for (int i = 0; i < size; i++) results.Add(new List<Result>());
foreach (var input in inputs)
{
for (int j = 0; j < input.Ids.Count; j++)
{
for (int i = 0; i < (size / input.Ids.Count); i++)
{
var x = new Result() { Label = input.Label, Id = input.Ids[j] };
results[(input.Ids.Count * i) + j].Add(x);
}
}
}
return results;
}
public static int factorial_WhileLoop(int number)
{
var result = 1;
while (number != 1)
{
result = result * number;
number = number - 1;
}
return result;
}

Linq query - List within List [duplicate]

This question already has answers here:
Group by in LINQ
(11 answers)
Closed 5 years ago.
I'm trying to select a list that contains Fund.Name and List<Investment>.
var funds = new List<Fund>
{
new Fund { Id = 1 , Name = "good" },
new Fund { Id = 2, Name = "bad" }
};
var investments = new List<Investment>
{
new Investment { Fund = funds[0], Value = 100 },
new Investment { Fund = funds[0], Value = 200 },
new Investment { Fund = funds[1], Value = 300 }
};
Then I'm trying to create the query with this:
var query = from f in funds
join i in investments
on f.Id equals i.Fund.Id
select new { f.Name, i };
I wanted something like this:
{ Name = good, {{ Id = 1, Value = 100 }, { Id = 1, Value = 200 }}},
{ Name = bad, { Id = 2, Value = 300 }}
But I'm getting something like this:
{ Name = good, { Id = 1, Value = 100 }},
{ Name = good, { Id = 1, Value = 200 }},
{ Name = bad, { Id = 2, Value = 300 }}
Try using GroupJoin.
var query = funds.GroupJoin(investments, f => f.Id, i => i.Fund.Id, (f, result) => new { f.Name, result });

Linq Find Partial Text Match - Included code returns duplicate and everything except what it should

I'm Trying to find a match (on a partial string) to see which Orders have not been processed.
The problem comes in line "where a.OrderNo.IndexOf(b) >=0"
It returns only the Already Processed - which is what I want to exclude.
Prefix2/OrderNo2
Prefix1/OrderNo4
If I change it to "where a.OrderNo.IndexOf(b) < 0" - then it returns duplicates of Items that are not in "AlreadyProcessed"
Prefix1/OrderNo1
Prefix1/OrderNo1
Prefix2/OrderNo2
Prefix2/OrderNo3
Prefix2/OrderNo3
Prefix1/OrderNo4
How can I change the Linq to only show Items that still need to be processed?
Why is this happening (so that I can learn from this please)
void Main()
{
RunThis();
}
public class Order
{
public string OrderNo;
public int CustomerID;
}
private void RunThis()
{
List<Order> o = new List<Order>()
{
new Order { OrderNo = "Prefix1/OrderNo1",CustomerID = 1},
new Order { OrderNo = "Prefix2/OrderNo2",CustomerID = 7},
new Order { OrderNo = "Prefix2/OrderNo3",CustomerID = 8},
new Order { OrderNo = "Prefix1/OrderNo4",CustomerID = 12},
};
List<string> AlreadyProcessed = new List<string>()
{
"OrderNo2",
"OrderNo4"
};
var ToBeProcessed = from a in o
from b in AlreadyProcessed
where a.OrderNo.IndexOf(b) >=0
select a.OrderNo;
Console.WriteLine(ToBeProcessed);
}
This will work:
List<Order> orders = new List<Order>()
{
new Order { OrderNo = "Prefix1/OrderNo1",CustomerID = 1},
new Order { OrderNo = "Prefix2/OrderNo2",CustomerID = 7},
new Order { OrderNo = "Prefix2/OrderNo3",CustomerID = 8},
new Order { OrderNo = "Prefix1/OrderNo4",CustomerID = 12},
};
List<string> AlreadyProcessed = new List<string>()
{
"OrderNo2",
"OrderNo4"
};
var ToBeProcessed = orders.Where(o => !AlreadyProcessed.Any(ap => o.OrderNo.Contains(ap)))
.Select(o => o.OrderNo);

Categories