How to add an order(autoIncrement) property to collection using Linq? - c#

Having:
Initialize an anonymouse collection (I would send it as json)
var myCollection = new[]
{
new
{
Code = 0,
Name = "",
OtherAttribute = ""
}
}.ToList();
myCollection.Clear();
And get the data.
myCollection = (from iPeople in ctx.Person
join iAnotherTable in ctx.OtherTable
on iPeople.Fk equals iAnotherTable.FK
...
order by iPeople.Name ascending
select new
{
Code = iPeople.Code,
Name = iPeople.Name,
OtherAttribute = iAnotherTable.OtherAtribute
}).ToList();
I want to add an Identity column, I need the collection ordered and a counted from 1 to collection.count. Is for binding this counter to a Column in a table (jtable).
var myCollection = new[]
{
new
{
Identity = 0,
Code = 0,
Name = "",
OtherAttribute = ""
}
}.ToList();
myCollection = (from iPeople in ctx.Person
join iAnotherTable in ctx.OtherTable
on iPeople.Fk equals iAnotherTable.FK
...
order by iPeople.Name ascending
select new
{
Identity = Enum.Range(1 to n)//Here I donĀ“t know how to do; in pl/sql would be rownum, but in Linq to SQL how?
Code = iPeople.Code,
Name = iPeople.Name,
OtherAttribute = iAnotherTable.OtherAtribute
}).ToList();

If you are using linq to entities or linq to sql, get your data from the server and ToList() it.
Most likely this answer will not translate to sql but I have not tried it.
List<string> myCollection = new List<string>();
myCollection.Add("hello");
myCollection.Add("world");
var result = myCollection.Select((s, i) => new { Identity = i, Value = s }).ToList();

As Simon suggest in comment, that could would look like below:
int counter = 0; //or 1.
myCollection = (from iPeople in ctx.Person
join iAnotherTable in ctx.OtherTable
on iPeople.Fk equals iAnotherTable.FK
...
order by iPeople.Name ascending
select new
{
Identity = counter++,
Code = iPeople.Code,
Name = iPeople.Name,
OtherAttribute = iAnotherTable.OtherAtribute
}).ToList();
Is there any problem in executing this kind of code?

As Simon stated in his comments, consider the following, albeit contrived, example:
int i = 0;
var collection = Enumerable.Range(0, 10).Select(x => new { Id = ++i });

One solution that helped me to achieve the same goal:
Create a separate Function like this:
private int getMaterialOrder(ref int order)
{
return order++;
}
Then call it in your linq query like:
...
select new MaterialItem() { Order=getMaterialOrder(ref order),
...

Related

Using LINQ to get information from two tables, with a join

I have a linq statement to populate two labels. The thing is, this information comes from two tables. I Have a join to join the two tables, except i cant get my Terms and Conditions from my Campaign table. Its only picking up the RedemptionLog table columns. Anyone to help with this?
MSCDatabaseDataContext MSCDB = new MSCDatabaseDataContext();
var q = from row in MSCDB.Tbl_RedemptionLogs
join d in MSCDB.Tbl_Campaigns on row.CampaignId equals d.CampaignId
orderby row.VoucherCode descending
select row;
var SeshVoucherDisplay = q.First();
lblCode.Text = SeshVoucherDisplay.VoucherCode;
lblTerms.Text = SeshVoucherDisplay
For the SeshVoucherDisplay variable, it only picks up from the RedemptionLogs table, yet i did a join? Any help?
Try something like this :
var SupJoin = from row in MSCDB.Tbl_RedemptionLogs
join d in MSCDB.Tbl_Campaigns on row.CampaignId equals d.CampaignId
orderby row.VoucherCode descending
select new { Id = row.ID, SupplierName = row.SupplierName,
CustomerName = d.CompanyName };
The column names are just for example purpose. Put your own there. And thereafter, you can apply First on it and use that particular variable.
Hope this helps.
Well, by writing select row you asked LINQ to give back to you only row.
If you want both elements, you need to ask for both of them, e.g. by writing select new { row, d }.
In this example
var foo =
new []
{
new { Id = 1, Name = "a" },
new { Id = 2, Name = "b" },
new { Id = 3, Name = "c" }
};
var bar =
new []
{
new { Id = 1, Name = "d" },
new { Id = 2, Name = "e" },
new { Id = 3, Name = "f" }
};
var baz =
from a in foo
join b in bar on a.Id equals b.Id
select new { a, b };
var qux =
from a in foo
join b in bar on a.Id equals b.Id
select new { a, b };
In baz you'll find only a list of foos, in qux you'll find a list of both foos and their bar.
Try this:
var query = (from row in MSCDB.Tbl_RedemptionLogs
join d in MSCDB.Tbl_Campaigns on row.CampaignId equals d.CampaignId)
orderby row.VoucherCode descending
select new
{
columnname = row.columnname
});
When writing select row you relate to the row you defined in from row in MSCDB.Tbl_RedemptionLogs.
However if you want the data from both tables you have to write something similar to this:
select new {
// the properties of row
Redemption = row.redemption,
// the properties of d
Campaign = d.CampaignID // alternativly use may also use row.CampaignID, but I wanted to show you may acces all the members from d also
}

How to union two LINQ queries but the second query need have more fields

I need make union between two LINQ queries, but the second query need have more fields that the first. How can I do it?
Example:
public static void Dummy()
{
var query1 = this.Db.Table1.Select(s => new MyObject() { A = s.Field1, B = s.Field2 });
var query2 = this.Db.Table2.Select(s => new MyObject() { A = s.Field1, B = s.Field2, C = s.Field3 });
var result = query1.Union(query2);
}
When I calls result.ToList(), occurs the following error:
The type 'MyObject' appears in two structurally incompatible
initializations within a single LINQ to Entities query. A type can be
initialized in two places in the same query, but only if the same
properties are set in both places and those properties are set in the
same order.
How Can I resolve this problem?
Obs.: I can't put the Field3 in the query1 (I don't have access to the query one, because this I Can't changed it)
You don't have to put Field3 in first query but Union requires same number of columns and in same order. Specify a dummy value for third column/field C like:
var query1 = this.Db.Table1.Select(s => new MyObject()
{ A = s.Field1, B = s.Field2 , C= ""});
Assign C whatever is the default value of Field3, may be null for reference type and 0 for numbers etc.
If you don't have access to it modify query1 then create a new query using query1 like:
var newQuery = query1.Select(s=> new MyObject()
{ A = A, B = B , C= ""});
and then use that in Union
var result = newQuery.Union(query2);
As-is, you can't. You can only union 2 sets that have the same structure. If you don't mind modifying query1, however:
var query1 = this.Db.Table1.Select(s => new MyObject()
{ A = s.Field1, B = s.Field2, C = null });
This would allow them to union properly, as they have the same structure.
You can do it, like this:
Create a object devired from MyObject
class MyObjectUnion : MyObject{
}
So, the method goes like this:
public static void Dummy()
{
var query1 = this.Db.Table1.Select(s => new MyObject() { A = s.Field1, B = s.Field2 });
var query1modified = this.Db.Table2.Select(s => new MyObjectUnion() { A = s.Field1, B = s.Field2, C = null });
var query2 = this.Db.Table2.Select(s => new MyObjectUnion() { A = s.Field1, B = s.Field2, C = s.Field3 });
var result = query1modified.Union(query2);
}
It works
Because records in query1 will never have a property "C", and all records in query2 will have a property "C", it is unlikely that a record in query1 will be equivalent to a record in query2. The only reason for using Union over Concat is to remove duplicates and since you can't have any, you should likely be using Concat instead of Union.
public static void Dummy()
{
var query1 = this.Db.Table1.Select(s => new MyObject() { A = s.Field1, B = s.Field2 });
var query2 = this.Db.Table2.Select(s => new MyObject() { A = s.Field1, B = s.Field2, C = s.Field3 });
var result = query1.ToList().Concat(query2);
}
There are exceptions, as if you have a custom IEqualityComparer for MyObject that ignores the "C" property, or the default for the "C" property may exist in a record for table2, and you wanted to remove the duplicate, or if there possibly exists duplicates within either query1 or query2 and you wanted them removed then you can still use Concat, but you need to use Distinct before the Concat.
Editted to force query1 to be materialized before concatenation via .ToList()
Double checked with LinqPad, and the following executable had no issues, using a datasource that had both Categories and Cities tables of which were completely different schemas:
void Main()
{
var query1 = Categories.Select(s => new MyObject { A = s.id, B = s.name });
var query2 = Cities.Select(s => new MyObject { A = s.id, B = s.city_name, C = s.location });
var result = query1.ToList().Concat(query2);
result.Dump();
}
public class MyObject
{
public int A {get;set;}
public string B {get;set;}
public object C {get;set;}
}

How to get rows from a list containing each couple of value in LINQ?

I have a list of "Couple" with the following structure
public class Couple
{
public string Code;
public string Label;
}
And another list of "Stuff" like that
public class Stuff
{
public string CodeStuff;
public string LabelStuff;
public int foo;
public int bar;
//etc...
}
I want to get all the Stuff objects where each couples (Code, Label) in my List<Couple> match with (CodeStuff, Label,Stuff) from List<Stuff>.
For example the Couple
Couple c = new Couple { Code = "ABC", Label = "MyLabel1" };
will match with the first row only from
Stuff s1 = new { CodeStuff = "ABC", LabelStuff = "MyLabel1" }; // OK
Stuff s1 = new { CodeStuff = "ABC", LabelStuff = "MyLabel2" }; // NOT OK
Stuff s1 = new { CodeStuff = "DEF", LabelStuff = "MyLabel1" }; // NOT OK
I tried to use .Where clause or .Foreach but I don't know how to get the couple (Code,Label) together. Can you help me ?
You need to use linq join.
List<Couple> lstcouple = new List<Couple>();
List<Stuff> lstStuff = new List<Stuff>();
var result = (from s in lstStuff
join c in lstcouple on new { CS = s.CodeStuff, LS = s.LabelStuff } equals new { CS = c.Code, LS = c.Label }
select s).ToList();
Have you tried a join? might need tweaking, but as an idea:
var joined = from c in couplesList
join s in stuffList on c.Code equals s.CodeStuff
where c.Label == s.LabelStuff
select s;
Try this:
List<Stuff> stuffs = new List<Stuff>{s1,s2,s3};
List<Couple> couples = new List<Couple>{c};
var filteredList = stuffs.
Where
(x=> couples.Any(y => y.Code == x.CodeStuff)
&& couples.Any(y=> y.Label == x.LabelStuff)
).ToList();

Linq to SQL in C# Unique data

I have a long list with ships that I get from a Linq to SQL query, but I only want one row per ImoNo. Today i have about 4 rows per ImoNo. I just need the one row that has been last updated (so in this example I need 2013-01-27).
This is my Linq To SQL query:
var res = from positions in context.Lloyds_ETAs
join vessels in context.Lloyds_Vessels on positions.ImoNumber equals vessels.imo_no
select new PositionData {
ImoNo = positions.ImoNumber,
PositionCordinates = positions.AIS_Latest_Position,
CompassOverGround = positions.Compass_over_Ground_Heading,
VesselId = positions.Vessel_ID,
Equipment = vessels.vessel_type,
Updated = positions.Last_Place_Location
};
return res.ToList();
var res = (from positions in context.Lloyds_ETAs
join vessels in context.Lloyds_Vessels on positions.ImoNumber equals vessels.imo_no
select new PositionData {
ImoNo = positions.ImoNumber,
PositionCordinates = positions.AIS_Latest_Position,
CompassOverGround = positions.Compass_over_Ground_Heading,
VesselId = positions.Vessel_ID,
Equipment = vessels.vessel_type,
Updated = positions.Last_Place_Location
})
.GroupBy(x => x.ImoNo)
.Select(g => g.OrderByDescending(pd => pd.Updated).First());
If you want the last one, all you have to do is append .OrderBy(pd => pd.Updated).Last() after your select.
var res = (from positions in context.Lloyds_ETAs
join vessels in context.Lloyds_Vessels on positions.ImoNumber equals vessels.imo_no
select new PositionData {
ImoNo = positions.ImoNumber,
PositionCordinates = positions.AIS_Latest_Position,
CompassOverGround = positions.Compass_over_Ground_Heading,
VesselId = positions.Vessel_ID,
Equipment = vessels.vessel_type,
Updated = positions.Last_Place_Location
}).OrderBy(pd => pd.Updated).Last();
return res.ToList();
(yourQuery).OrderByDescending(pd=>pd.Updated).First()
There are several ways to get just one "row" as a result:
res.OrderByDescending(x => x.Updated).Take(1);
res.OrderByDescending(x => x.Updated).First();
res.Order(x => x.Updated).Last();
It seems that you have some duplication though, so maybe doing a group by would be more appropriate.

how to convert List<SomeType> to List<AnotherType>?

I have two data types:
class MyDataType {
public int Id;
private int Field;
public String AnotherFieldOrProperty;
// + there are some methods
}
class MyDataTypeDescriptor {
public int Id;
public String Description;
}
I need to convert List<MyDataType> to List<MyDataTypeDescriptor> such a way:
MyDataTypeDescriptor.Id = MyDataType.Id
MyDataTypeDescriptor.Description = MyDataType.ToString();
I guess C# can do that very easy and fast in just one line of code, but I don't know how because I'm not familar with such advanced techniques. Would someone help me please?
Thanks
This should do it (where myDataTypes is your List<MyDataType>):
List<MyDataTypeDescriptor> myDataTypeDescriptors =
myDataTypes.Select(x => new MyDataTypeDescriptor
{
Id = x.Id,
Description = x.ToString()
}).ToList();
(from i in list1
select new MyDataTypeDescriptor { Id = i.Id, Description = i.ToString()).ToList();
You can use automapper to do this automagically for you if you don't want to write the iterator yourself..
You can do it by using LINQ Select method:
List<MyDataType> list;
// Process list...
List<MyDataTypeDescriptor> result =
list.Select(x => new MyDataTypeDescriptor() { Id = x.Id, Description = x.ToString() }).
ToList<MyDataTypeDescriptor>();
Or if you have a constructor for MyDataTypeDescriptor that takes an Id and a Description:
List<MyDataType> list;
// Process list...
List<MyDataTypeDescriptor> result =
list.Select(x => new MyDataTypeDescriptor(x.Id, x.ToString())).
ToList<MyDataTypeDescriptor>();
For simple conversions, you can use the Select method like this:
List<int> lstA = new List<int>();
List<string> lstB = lstA.Select(x => x.ToString()).ToList();
For more compex conversions, you the ConvertAll function, like this:
List<int> lstA = new List<int>();
List<string> lstB = lstA.ConvertAll<string>(new Converter<int, string>(StringToInt));
public static string StringToInt(int value)
{
return value.ToString();
}
You can do this with LINQ:
var listofMyDataTypeDescriptor = (from m in listOfMyDataType
select new MyDataTypeDescriptor()
{
Id = m.Id,
Description = m.ToString()
}).ToList();
You can't actually convert them, you'll have to iterate through the collection and create a new Descriptor for each DataType
var result = (from MyDataType m in listOfMyDataType select new MyDataTypeDescriptor
{
Id = m.Id,
Description = m.toString(),
}).ToList();
Just to add one more way
define an explicit user type conversion
MSDN
then do
var newlist = MyDataTypleList.Cast<MyDataTypeDescriptor>().ToList();

Categories