I'm currently working to add Data to a GridView. The data comes from 2 tables that are on different databases. Currently I am able to populate the first entry, but it does not populate past that. here is the code:
void FillOrder(int inv)
{
var _ord = new OrdersContext();
var _pro = new ProductContext();
var qryOrder = (from o in _ord.OrderDetails
where o.InvNumberId == inv
select new
{
o.ProductID,
o.Quantity
}).ToList();
foreach (var order in qryOrder)
{
int prodID = order.ProductID;
int itemCount = qryOrder.Count;
var qryProducts = (from p in _pro.Products
where p.ProductID == prodID
select new
{
p.ProductID,
p.ProductName
}).ToList();
var results = (from t in qryOrder
join s in qryProducts
on t.ProductID equals prodID
select new
{
t.ProductID,
t.Quantity,
s.ProductName
}).ToList();
OrderItemList.DataSource = results;
OrderItemList.DataBind();
}
}
Can anyone help as to why it's only populating the first entry?
If the number of products involved is relatively small, (and since this query seems to be relate to one invoice, I would think that is true), then you can probably use something like the code below.
This is removing the loop, but the contains method will probably generate a SQL statement something like select ProductID, ProductName from products where productID in (,,,,,,) so may fail if the number of parameters is extremely large.
var _ord = new OrdersContext();
var _pro = new ProductContext();
var qryOrder = (from o in _ord.OrderDetails
where o.InvNumberId == inv
select new
{
o.ProductID,
o.Quantity
}).ToList();
// Get the productIDs
var productIDS = qryOrder.Select(o=>o.ProductID).Distinct().ToList();
// Get the details of the products used.
var qryProducts = (from p in _pro.Products
where productIDS.Contains(p.ProductID)
select new
{
p.ProductID,
p.ProductName
}).ToList();
// Combine the two in memory lists
var results = (from t in qryOrder
join s in qryProducts
on t.ProductID equals s.ProductID
select new
{
t.ProductID,
t.Quantity,
s.ProductName
}).ToList();
OrderItemList.DataSource = results;
OrderItemList.DataBind();
Looking for a bit of advice on grouping with entity framework and linq.
So i have a table "tbl_ChatLog" that contains userID and sendToUserID etc...and with this data i'm trying to display the "Top 1" from each "SendToUserID"
So in my UI it would look like so:
1001 (Contains multiple but show the top 1)
1003 (Contains multiple but show the top 1)
1008 (Contains multiple but show the top 1)
1009 (Contains multiple but show the top 1)
The start of my code below:
public static List<Chat> getChatMessage()
{
var entities = new FreeEntities();
//My ID
Business.User user = Business.User.getUserBySecurityToken();
List<Chat> chatMessages =
(
from cm in entities.tbl_ChatLog
where cm.UserID == user.uid
select new Chat
{
uid = (int)cm.UserID,
sendToUserID = (int)cm.SendToUserID,
message = cm.Message, dateAdded = (DateTime)cm.DateAdded
}
).OrderByDescending(x => x.dateAdded).ToList();
return chatMessages;
}
Hoping you can help me out on this one. Grouping always seems to throw me.
Much appreciated,
Terry
You could use groupby:
List<Chat> chatMessages =
(from cm in entities.tbl_ChatLog
where cm.UserID == user.uid
orderby cm.DateAdded descending
group cm by cm.sendToUserID into grp
select new Chat
{
uid = grp.FirstOrDefault().UserID,
sendToUserID = grp.Key,
message = grp.FirstOrDefault().Message,
dateAdded = grp.FirstOrDefault().DateAdded
}).ToList()
This will get you a list of your table data grouped by sendToUserID and the first entry of each group containing every property including sendToUserID.
The original problem was trying to select the first message from each unique "SendToUserId" and grouping by UserId and then selecting into a DTO was a nightmare but i managed to get a simple work around. Code below:
getFirstChatMessage()
{
var entities = new FreeEntities();
//User ID
Business.User user = Business.User.getUserBySecurityToken();
// Create new list of Chat
List<Chat> chatList = new List<Chat>();
var res = from c in entities.tbl_ChatLog
where c.UserID == user.uid
group c by c.UserID
into groups
select groups.OrderByDescending(p => p.DateAdded).FirstOrDefault();
foreach (var r in res)
{
chatList.Add(new Chat()
{
uid = (int)r.UserID,
sendToUserID = (int)r.SendToUserID,
message = (from m in entities.tbl_ChatLog where m.UserID == (int)r.SendToUserID
orderby r.DateAdded descending select m.Message).FirstOrDefault(),
dateAdded = (DateTime)r.DateAdded,
fullName = (from b in entities.tbl_Bio where b.UserID == (int)r.SendToUserID
select b.FirstName + " " + b.SurName).FirstOrDefault()
});
}
return chatList;
}
I am trying to convert below SQL query into Linq.
select eg.userid, eg.groupid, count(r.RID) as RecipientCount
from eg
join g on eg.groupid = g.groupid
join r on g.RID = r.RID
where eg.UserId = '7F813844-3B93-418E-8141-654082C4E37D'
and eg.IsDeleted = 0
and r.Isdeleted = 0
group by eg.groupid
Above query runs properly in SQL.
My Linq code is:
var v = from eml in dc.egs
join recpingroup in dc.g on eml.GroupID equals recpingroup.GroupID
where eml.aspnet_User.LoweredUserName.Equals(strUserName.ToLower())
&& !eml.IsDeleted
&& !recpingroup.r.IsDeleted
select new Info()
{
CreateDt = eml.CreateDt.ToShortDateString(),
UserId = eml.UserId.ToString(),
LastUpdateDt = eml.LastUpdateDt.ToShortDateString(),
Username = eml.aspnet_User.UserName,
GroupDescription = eml.GroupDescription,
GroupID = eml.GroupID.ToString().ToUpper(),
GroupName = eml.GroupName,
Count = dc.g.Count(r1 => r1.GroupID.Equals(eml.GroupID) && !r1.r.IsDeleted)
};
where dc is my DataContext.
But I am having problems in the last property i.e. Count is coming wrong. I want the counts of recipients from recpingroup.r as RecipientCount.
Also note that tables are linked in SQL internally by PK and FK references.
try following
Count = (from x in dc.g where(r1 => r1.GroupID.Equals(eml.GroupID) && !r1.r.IsDeleted) select x.g).count()
I need to select data from different tables associated, I have a hospital table, another specialty, and other services, and what is held to select all hospitals and their specialties and services, there is a way to do this in linq?
this is what I'm trying
var hospitalesQuery = from hospital in App.ViewModel.ChristusDB.Hospitales
where hospital.id_tipo == "2" && hospital.christus == "1"
orderby hospital.distancia ascending
from e in App.ViewModel.ChristusDB.EspHosp
where e.fk_hospital==hospital.pk_hospital
from s in App.ViewModel.ChristusDB.ServHosp
where s.fk_hospital==hospital.pk_hospital
select new Hospitale()
{
pk_hospital = hospital.pk_hospital,
nombre = hospital.nombre,
direccion = hospital.direccion,
ciudad = hospital.ciudad,
id_ciudad = hospital.id_ciudad,
estado = hospital.estado,
id_estado = hospital.id_estado,
id_tipo = hospital.id_tipo,
tipo_descripcion = hospital.tipo_descripcion,
imagen = hospital.imagen,
gps_lat = hospital.gps_lat,
gps_lng = hospital.gps_lng,
abierto_lv = hospital.abierto_lv,
abierto_sd = hospital.abierto_sd,
telefono_1 = hospital.telefono_1,
telefono_2 = hospital.telefono_2,
telefono_3 = hospital.telefono_3,
telefono_4 = hospital.telefono_4,
telefono_5 = hospital.telefono_5,
inactivo = hospital.inactivo,
christus = hospital.christus,
especialidades= new List<Especialidade>(e),
servicios= new List<Servicio>(s)
};
You are looking for joining tables by a foreign key. LINQ (asn SQL as well) provide join for this:
from hospital in App.ViewModel.ChristusDB.Hospitales
where hospital.id_tipo == "2" && hospital.christus == "1"
join e in App.ViewModel.ChristusDB.EspHosp on hospital.pk_hospital equals e.fk_hospital
join s in App.ViewModel.ChristusDB.ServHosp on hospital.pk_hospital on s.fk_hospital
orderby hospital.distancia ascending
select new Hospitale()
{...
Update. If you want to load list dependencies for each of the hospitals, I do not think you can do this with one query in EF. This is as close as you can get:
var hospitals = (from hospital in App.ViewModel.ChristusDB.Hospitales
where hospital.id_tipo == "2" && hospital.christus == "1"
orderby hospital.distancia ascending
select new Hospitale()
{
pk_hospital = hospital.pk_hospital,
...
}).ToList();
foreach (var h in hospitals)
{
h.especialidades = App.ViewModel.ChristusDB.EspHosp.Where(e => e.fk_hospital==h.pk_hospital).ToList();
h.servicios = App.ViewModel.ChristusDB.ServHosp.Where(e => s.fk_hospital==h.pk_hospital).ToList();
}
However this would be a lot of queries to the DB, which might perform poorly. You should really think about redesigning your EF data model properly so that the framework does this job of loading dependencies for you.
I have a Linq query that needs optimizing.
Edit
I guess over all what I am trying to do is select all the rows in the first table, but select the last or default row in Survey, CB and Science tables...
Edit
When this creates a query, I hit the database once for the entire query and then once more for EVERY single result I get back from the first query. So if TestClass returns 30 results, I then hit the DB 30 more times for the Survey Object.
I really need a better way to make this work.
Thanks in advance!
Example Query
return (from xx in db.test
select new TestClass {
Added_By_User_ID = xx.Added_By_User_ID,
Survey = (from ru in db.Utopia
where ru.Province_ID == xx.Province_ID
orderby ru.uid descending
select ru).Take(1).ToList(),
}).ToList();
Real Query
return (from xx in db.Utopia_Province_Data_Captured_Gens
where xx.Owner_Kingdom_ID == ownerKingdomID
where kingdomList.Contains((Guid)xx.Kingdom_ID)
select new ProvinceClass
{
Kingdom_ID = xx.Kingdom_ID,
Kingdom_Island = xx.Kingdom_Island,
Kingdom_Location = xx.Kingdom_Location,
Owner_Kingdom_ID = xx.Owner_Kingdom_ID,
Province_ID = xx.Province_ID,
Province_Name = xx.Province_Name,
Owner_User_ID = xx.Owner_User_ID,
Race_ID = xx.Race_ID,
Updated_By_DateTime = xx.Updated_By_DateTime,
Networth = xx.Networth,
Land = xx.Land,
Monarch_Display = xx.Monarch_Display,
Owner = xx.Owner,
Sub_Monarch = xx.Sub_Monarch,
CB_Updated_By_Province_ID = xx.CB_Updated_By_Province_ID,
uid = xx.uid,
Formatted_By = xx.Formatted_By,
Utopian_Day_Month = xx.Utopian_Day_Month,
Utopian_Year = xx.Utopian_Year,
Ruler_Name = xx.Ruler_Name,
Personality_ID = xx.Personality_ID,
Nobility_ID = xx.Nobility_ID,
Money = xx.Money,
Daily_Income = xx.Daily_Income,
Food = xx.Food,
Runes = xx.Runes,
Population = xx.Population,
Peasents = xx.Peasents,
Peasents_Non_Percentage = xx.Peasents_Non_Percentage,
Trade_Balance = xx.Trade_Balance,
Building_Effectiveness = xx.Building_Effectiveness,
Military_Efficiency_Off = xx.Military_Efficiency_Off,
Military_Efficiency_Def = xx.Military_Efficiency_Def,
Draft = xx.Draft,
Soldiers = xx.Soldiers,
Soldiers_Regs_Off = xx.Soldiers_Regs_Off,
Soldiers_Regs_Def = xx.Soldiers_Regs_Def,
Soldiers_Elites = xx.Soldiers_Elites,
War_Horses = xx.War_Horses,
//Prisoners = xx.Prisoners,
Military_Net_Off = xx.Military_Net_Off,
Military_Net_Def = xx.Military_Net_Def,
Military_Current_Off = xx.Military_Current_Off,
Military_Current_Def = xx.Military_Current_Def,
Mil_Training = xx.Mil_Training,
Mil_Wage = xx.Mil_Wage,
Mil_Overall_Efficiency = xx.Mil_Overall_Efficiency,
Mil_Total_Generals = xx.Mil_Total_Generals,
Wizards = xx.Wizards,
Wizards_Value_Type = xx.Wizards_Value_Type,
Thieves = xx.Thieves,
Thieves_Value_Type = xx.Thieves_Value_Type,
Plague = xx.Plague,
Monarch_Vote_Province_ID = xx.Monarch_Vote_Province_ID,
Protected = xx.Protected,
Hit = xx.Hit,
Honor = xx.Honor,
Province_Notes = xx.Province_Notes,
CB_Export_Line = xx.CB_Export_Line,
Army_Out = xx.Army_Out,
Army_Out_Expires = xx.Army_Out_Expires,
Updated_By_Province_ID = xx.Updated_By_Province_ID,
SOM_Updated_By_Province_ID = xx.SOM_Updated_By_Province_ID,
SOM_Updated_By_DateTime = xx.SOM_Updated_By_DateTime,
CB_Updated_By_DateTime = xx.CB_Updated_By_DateTime,
CB_Requested = xx.CB_Requested,
CB_Requested_Province_ID = xx.CB_Requested_Province_ID,
SOM_Requested = xx.SOM_Requested,
SOM_Requested_Province_ID = xx.SOM_Requested_Province_ID,
SOS_Requested = xx.SOS_Requested,
SOS_Requested_Province_ID = xx.SOS_Requested_Province_ID,
Survey_Requested = xx.Survey_Requested,
Survey_Requested_Province_ID = xx.Survey_Requested_Province_ID,
Last_Login_For_Province = xx.Last_Login_For_Province,
Date_Time_User_ID_Linked = xx.Date_Time_User_ID_Linked,
Added_By_User_ID = xx.Added_By_User_ID,
NoteCount = (from yy in db.Utopia_Province_Notes
where yy.Province_ID == xx.Province_ID
select yy).Count(),
SOM = (from uu in db.Utopia_Province_Data_Captured_Type_Militaries
where uu.Province_ID == xx.Province_ID
where uu.Owner_Kingdom_ID == ownerKingdomID
where uu.DateTime_Added == (from ru in db.Utopia_Province_Data_Captured_Type_Militaries //datetime can be same for multiple items.
where ru.Province_ID == xx.Province_ID
where ru.Owner_Kingdom_ID == ownerKingdomID
orderby ru.uid descending // To get the last most inserted rows
select ru.DateTime_Added).FirstOrDefault()
select uu).ToList(),
SOS = (from zz in db.Utopia_Province_Data_Captured_Sciences
where ru.Province_ID == xx.Province_ID
where ru.Owner_Kingdom_ID == ownerKingdomID
orderby ru.uid descending
select ru).Take(1).ToList(),
Survey = (from ru in db.Utopia_Province_Data_Captured_Surveys
where ru.Province_ID == xx.Province_ID
where ru.Owner_Kingdom_ID == ownerKingdomID
orderby ru.uid descending
select ru).Take(1).ToList(),
CB = (from ru in db.Utopia_Province_Data_Captured_CBs
where ru.Province_ID == xx.Province_ID
where ru.Owner_Kingdom_ID == ownerKingdomID
orderby ru.uid descending
select ru).Take(1).ToList()
}).ToList();
You can select from your Utopia table and join the second one for getting the user_id like:
from ru in db.Utopia
join xx in test on ru.Province_ID equals xx.Province_ID
orderby ru.uid descending
select new TestClass
{
Added_By_User_ID = xx.Added_By_User_ID,
Survey = ru
}
Update for the real query
This is one massive query, you should consider an approach based on joins as i suggested and based on local caching as Jim McKeeth suggested. Or you should create a new table all together.
When you need to query from multiple tables with optional data, you can perform a left join:
from ru in db.Utopia
join user in db.Users on ru.UserId equals user.Id // User is required
join survey in db.Surveys on ru.Province_ID equals survey.Province_ID into j1
from survey in j1.DefaultIfEmpty() // Survey is optional (left join)
join address in db.Address on ru.UserId equals address.UserId into j2
from survey in j2.DefaultIfEmpty() // Address is optional (left join)
orderby ru.uid descending
select new TestClass
{
Added_By_User_ID = xx.Added_By_User_ID,
Survey = survey,
Street = address.Street,
UserName = new UserName
{
FirstName = user.FirstName,
LastName = user.LastName
}
}
Be aware that the amount of joins will influence the performance of your query. Sooner or later it will become more efficient do find a better way with caching.
Another note is that calling ToList() in your query will actually execute that part of the query (or the whole query).
Something like:
from xx in db.test
join ru in db.Utopia on xx.Province_ID equals ru.Province_ID
orderby ru.uid descending
select new ..
The complexity of your real query to me indicates you should be moving this LINQ statement into a stored procedure, then calling that instead.
I recommend this because (a) you will have complete control over the how the query executes and, (b) profiling and performance optimizing your query is much easier in TSQL. This is the strategy we have used in larger projects in the past when result-set generation becomes non-trivial.
I would also suggest you use AutoMapper to perform the task of transferring the sproc results into your DTO, because you appear to have a near 1:1 mapping