Nested Linq in c# - c#

I want to extract a list using linq as tree structure.
{
"details": [
{
"description":"This is description 1",
"Name": "Name 1"
},
{
"description":"This is description 2",
"Name": "Name 2"
}
],
"price": 100
}
I have one detailsDto as List<> in hand which i will use it in Details field
properties from 'm' instance will be bind in detailsDto. that's where i am facing problem on how to do it. description and name field available in 'm' instance
var data = await Task.FromResult((
from c in _context.C
join mc in _context.MC on c.VId equals mc.VId
join m in _context.M on mc.Id equals m.mcId
where mc.Id == mcId && c.Id == CId
select new MainDto()
{
Price = mc.Price,
// Details =
}
).FirstOrDefault()
);

Probably you need this query:
var data = await (
from c in _context.C
join mc in _context.MC on c.VId equals mc.VId
where mc.Id == mcId && c.Id == CId
select new MainDto()
{
Price = mc.Price,
Details = _context.M.Select(m => new DetailsDto
{
Name = m.Name,
description = m.Description,
}).ToList()
}
).FirstOrDefaultAsync();

this should be helpful
{
Price = mc.Price,
Details = m.Select(x => new DetailDto
{
Description = x.Description,
Name = x.Name
}).ToList()
}
It will create a new instance of the DetailDto class for each element in the m list and assign the values of the Description and Name properties to the corresponding properties in the DetailDto instance.

Related

How to call generic method like Find, FindAll

I an intermediate C# develop. I am trying to implement some methods in my program. But it's been giving sleepless nights. E.g
NB: I already declared the class properties ahead.
Employee employe = new Employee(){
ID = 111,
Name = "Eric Trump",
Gender = "Male",
Salary = 900000
};
Employee employe2 = new Employee()
{
ID = 112,
Name = "Ayo",
Gender = "Female",
Salary = 8900
};
List<Employee> listemp = new List<Employee>();
listemp.Add(employe);
listemp.Add(employe2);
How to i use the Find, FindAll() or FindLast()?
You can do that by passing a Predicate<T> delegate to Find, FindLast or FindAll methods
List<Employee> listemp = new List<Employee>();
listemp.Add(employe);
listemp.Add(employe2);
var result = listemp.FindLast(e => e.ID == 112); //or listemp.Find(e => e.ID == 112)
e => e.ID == 112 is called lambda expression, it's just a more convenient way to specify an anonymous delegate, you can find more details at Delegates and lambdas
Just use lambda-expressions:
List<string> lists = new List<string>()
{
"1", "2", "3"
};
var all = lists.FindAll(s => s == "1");
Read more about Find all here.
UPDATE:
Lambda-expression is a shorter way to represent anonymous methods. So you can use them like that:
List<Employee> employees = new List<Employee>()
{
new Employee(){
Id = 111,
Name = "Eric Trump",
Gender = "Male",
Salary = 900000
},
new Employee(){
Id = 112,
Name = "Ayo",
Gender = "Female",
Salary = 8900
}
};
var findAll = employees.FindAll(s => s.Id == 111);
var findLast = employees.FindLast(s => s.Id == 111);
var find = employees.Find(s => s.Id == 111);

Entity Framework Linq to Object Mapping

I have one problem.
Database Shema
==================
|parts |
==================
| partId |textId |
==================
========================
texts |
========================
|TextId|LanguageId|text|
========================
============================
languages |
============================
|LanguageId|LanguageIsoCode|
============================
I want to map this result to the following object
public long PartId { get; set; }
public Dictionary<string,string> Name { get; set; }
eg.
{
PartId: 32020
Name: {["en": "Blah", "es": "Blah2"]}
}
this is what I have tried, but Im running into TimeOut with this query.
var query = (from p in _context.epc_parts
select new //select first dynamic object
{
PartId = p.PartID,
Code = p.PartName,
Name = (from trans in _context.epc_texts
join lang in _context.epc_languages on trans.LanguageID equals lang.LanguageID
where p.TextID == trans.TextID
select new
{
LanguageId = lang.shortname.ToLower(),
Caption = trans.Caption
})
}).AsEnumerable().Select(x => new SearchPartModel //transform it here when we can use dictionary
{
Code = x.Code,
PartId = x.PartId,
Name = x.Name.ToDictionary(t => t.LanguageId, t => t.Caption)
});
The parts table has about 60k rows for every row there are 7 translations. Navigation properties cant be used because the Shema doesn't use foreign keys and the model is generated from db.
I have solved it with this query. For the whole query it took about 20s to load everything what is ok for this purpose. Im using group by first.
(from p in _context.epc_parts
join trans in _context.epc_texts on p.TextID equals trans.TextID
join lang in _context.epc_languages on trans.LanguageID equals lang.LanguageID
select new
{
PartId = p.PartID,
Code = p.PartName,
Caption = trans.Caption,
LanguageId = lang.shortname.ToLower()
}).AsEnumerable().GroupBy(x => x.PartId).Select(g => new SearchPartModel
{
Code = g.Select(x => x.Code).FirstOrDefault(),
PartId = g.Key,
Name = g.Select(x => new
{
x.LanguageId,
x.Caption
}).Distinct().ToDictionary(y => y.LanguageId, y => y.Caption)
});
from p in _context.epc_parts
join trans in _context.epc_texts on p.TextID equals trans.TextID
join lang in _context.epc_languages on trans.LanguageID equals lang.LanguageID
select new {
PartId = p.PartID,
Code = p.PartName,
Name = new
{
LanguageId = lang.shortname.ToLower(),
Caption = trans.Caption
}
}
That should be better, otherwise in your current implementation for each part you're querying the texts table

Put joined rows into a merged list

I have the LINQ to SQL query below which works fine, except that I would like to get the "items" selected from "table3" to be put into a single entity object, instead what I'm getting is a new entity with the same Id but different item for each row.
What do I need to do to achieve this?
Thanks!
var result =
from table1 in db.Table1
join table2 in db.Table2 on table1.fkId equals table2.fkId
join table3 in db.Table3 on table2.fkAid equals table3.Id into items
select new Entity
{
Id = table1.Id,
Name = table1.Name,
Items = items.Select(x => new AEntity { Id = x.Id, Name = x.Name }).ToList()
};
return result.ToList();
Edit to elaborate:
From the code above I could get, for example, the following result (pseudocode):
{
Entity
{
Id = 1,
Name = "1",
Items
{
AEntity
{
Name = "33"
Id = 33
}
}
},
Entity
{
Id = 1,
Name = "1",
Items
{
AEntity
{
Id = 44,
Name = "44"
}
}
},
Entity
{
Id = 2,
Name = "2",
Items
{
AEntity
{
Id = 55,
Name = "55"
}
}
}
}
But I want this:
{
Entity
{
Id = 1,
Name = "1",
Items
{
AEntity
{
Id = 33,
Name = "33"
},
AEntity
{
Id = 44,
Name = "44"
}
}
},
Entity
{
Id = 2,
Name = "2",
Items
{
AEntity
{
Id = 55,
Name = "55"
}
}
}
}
I hope that clarifies it a bit.
Once again another person falls victim to "trying to do SQL in Linq". The correct way to do this (in Linq) is...*
var items = context.Entities.Include(x => x.AEntities).ToList();
However if you ARE trying to learn to use an ORM, FOR THE LOVE OF ALL THAT IS HOLY DO NOT USE LINQ2SQL. Its broken, unsupported and out of date.
PLEASE USE Entity Framework.
Now you should google Entity Framework Many to Many or One to Many Associations.
Failing that...
var items = from item1 in db.Table1
select new
{
Id = table1.Id,
Name = table1.Name,
Items = db.Table3
.Where(x => db.Table2
.Where(t2 => t2.fkId == item1.fkId)
.Select(t2 => t2.fkAid)
.Contains(x.Id)).ToList()
};
But that just looks ugly.
*Table 2 looks like the age old pattern of, "Databases can't do Many to Many, so we are going to put in an intermediate table that has no data what-so-ever".

At least one object must implement IComparable error in linq query

var pairs = new [] { new { id = 1, name = "ram", dept = "IT", sal = "3000" }, new { id = 2, name = "ramesh", dept = "IT", sal = "5000" }, new { id = 3, name = "rahesh", dept = "NONIT", sal = "2000" },
new { id = 5, name = "rash", dept = "NONIT", sal = "7000" } };
var query = from stud in pairs
where (stud.name.StartsWith("r") && stud.id % 2 != 0)
//orderby stud.sal descending
group stud by stud.dept into grps
select new { Values = grps, Key = grps.Key, maxsal=grps.Max() };
////select new { id = stud.id };
foreach (dynamic result in query)
{
Console.WriteLine(result.Key);
Console.WriteLine(result.maxsal);
foreach (dynamic result2 in result.Values)
{
Console.WriteLine(result2.id + "," + result2.sal);
}
}
Console.Read();
I am getting the error "At least one object must implement IComparable.", can someone explain me why iam I getting this error ?
You are calling grps.Max() to get maximnum item in group. Your anonymous objects are not comparable. How Linq will know which one is maximum from them? Should it use id property for comparison, or name?
I believe you want to select max salary:
maxsal = grps.Max(s => Int32.Parse(s.sal))

LINQ - Left join and Group by and Sum

I have two lists                                                      
var stores = new[]
{
new { Code = 1, Name = "Store 1" },
new { Code = 2, Name = "Store 2" }
};
var orders = new[]
{
new { Code = 1, StoreCode = 1, TotalValue = 14.12 },
new { Code = 2, StoreCode = 1, TotalValue = 24.12 }
};
OUTPUT
StoreName = Store 1 | TotalValue = 38.24
StoreName = Store 2 | TotalValue = 0
How can I translate this into LINQ to SQL?                                             
var lj = (from s in stores
join o in orders on s.Code equals o.StoreCode into joined
from j in joined.DefaultIfEmpty()
group s by new
{
StoreCode = s.Code,
StoreName = s.Name
}
into grp
select new
{
StoreName = grp.Key.StoreName,
TotalValue = ???
}).ToList();
When you doing group join, all orders related to store will be in group, and you will have access to store object. So, simply use s.Name to get name of store, and g.Sum() to calculate total of orders:
var lj = (from s in db.stores
join o in db.orders on s.Code equals o.StoreCode into g
select new {
StoreCode = s.Name,
TotalValue = g.Sum(x => x.TotalValue)
}).ToList();
Note - from your sample it looks like you don't need to group by store name and code, because code looks like primary key and it's unlikely you will have several stores with same primary key but different names.

Categories