pagination in linq to sql into list - c#

I have a linq to sql query that performs several joins in several tables to return a me list of data. The query works fine and returns me all the correct data. However, I have decided to add pagination in my data table, and have modified the below code a bit, so that not all data is fetched from the db at once.
The issue that I am having is how to add the data returned by the query inside the var data into the allTrucks list correctly ?
The exception that I am having is the following :
Expression expected in Dynamic Linq
List<TruckList> allTrucks = new List<TruckList>();
try
{
using (PaginationContext _db = new PaginationContext())
{
var data = (from lad in _db.Jobs
join users in _db.Users on lad.Id equals users.Id into
ul
from users in ul.DefaultIfEmpty()
join ladAddressLoading in _db.Addresses.Where(a => a.TAD_N_ID == 1) on lad.Id equals ladAddressLoading.Id
join ladAddressDelivery in _db.Addresses.Where(a => a.TAD_N_ID == 2) on lad.Id equals ladAddressDelivery.Id
join countryLoading in _db.Countries on ladAddressLoading.Id equals countryLoading.Id
join countryDelivery in _db.Countries on ladAddressDelivery.Id equals countryDelivery.Id
join volume in _db.Measurements on lad.Id equals volume.Id
select new
{
Coordinator = users == null ? "No User" : users.FirstName + " " + users.LastName,
Volume = ladAddressLoading.VolumeTotal,
DeliveryCountry = countryDelivery.ISO2,
DeliveryDate = ladAddressDelivery.From,
LoadingCountry = countryLoading.ISO2,
LoadingDate = ladAddressLoading.From,
}).AsEnumerable()
.Select(x => new TruckList()
{
Coordinator = x.Coordinator,
Volume = x.Volume,
Delivery = x.DeliveryCountry + " - " + x.DeliveryDate.Value.ToString("dd/MM/yyyy"),
Loading = x.LoadingCountry + " - " + x.LoadingDate.Value.ToString("dd/MM/yyyy"),
});
allTrucks.AddRange(data);
totalRows = allTrucks.Count;
if (!string.IsNullOrEmpty(searchVal))
{
// filter
allTrucks = allTrucks.Where(x => x.FileID.ToLower().Contains(searchVal.ToLower())).ToList<TruckList>();
}
totalRowsAfterFilter = allTrucks.Count;
// sorting
allTrucks = allTrucks.OrderBy(sortColumnName + " " + sortDirection).ToList<TruckList>();
// paging
allTrucks = allTrucks.Skip(start).Take(length).ToList<TruckList>();
How can I assign the linq-to-sql directly to the List<TruckList> directly ?
Could someone advise a better approach of doing this ? Please help.

Break into two queries. The variable data is not a TruckList. See code below
var data = from lad in _db.Jobs
join users in _db.Users on lad.Id equals users.Id into ul
from users in ul.DefaultIfEmpty()
join ladAddressLoading in _db.Addresses.Where(a => a.TAD_N_ID == 1) on lad.Id equals ladAddressLoading.Id
join ladAddressDelivery in _db.Addresses.Where(a => a.TAD_N_ID == 2) on lad.Id equals ladAddressDelivery.Id
join countryLoading in _db.Countries on ladAddressLoading.Id equals countryLoading.Id
join countryDelivery in _db.Countries on ladAddressDelivery.Id equals countryDelivery.Id
join volume in _db.Measurements on lad.Id equals volume.Id
select new
{
Coordinator = users == null ? "No User" : users.FirstName + " " + users.LastName,
Volume = ladAddressLoading.VolumeTotal,
DeliveryCountry = countryDelivery.ISO2,
DeliveryDate = ladAddressDelivery.From,
LoadingCountry = countryLoading.ISO2,
LoadingDate = ladAddressLoading.From,
};
List<TruckList> trucks = data.Select(x => new TruckList()
{
Coordinator = x.Coordinator,
Volume = x.Volume,
Delivery = x.DeliveryCountry + " - " + x.DeliveryDate.Value.ToString("dd/MM/yyyy"),
Loading = x.LoadingCountry + " - " + x.LoadingDate.Value.ToString("dd/MM/yyyy"),
});
allTrucks.AddRange(trucks);

It's just like the exception says -- .OrderBy expects an Expression and you are passing a string.
allTrucks = allTrucks.OrderBy(sortColumnName + " " + sortDirection).ToList<TruckList>();
What it should be is something like
allTrucks = allTrucks.OrderBy(truck => truck.SomeProp).ToList();

Related

LinQ query - Cannot use Date as its non-primitive EDM type. Also cannot convert DateTime to String

I have below linQ Query for which I am getting the error:
LINQ to Entities does not recognize the method 'System.String ToString(System.DateTime)' method, and this method cannot be translated into a store expression.
var query = from i in Expenditure
join d in Department on i.DepartId equals d.dID
where i.Status == "Audit"
group i by new { i.InvoiceId, d.Title, i.InvoiceDate } into g
select new
{
id = g.Key.InvoiceId,
txt = g.Key.Title + " // " + g.Key.InvoiceId + " // " + Convert.ToString(g.Key.InvoiceDate)
};
I want txt output as follow:
Health // Inv001 // 12-03-2018
Education // Inv002 // 23-03-3018
Problem is with InvoiceDate (Datetime) field for which I initially wrote (without the Convert)as: g.Key.InvoiceDate
but I got error as: Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
Can anyone suggest an easy solution? Thanks.
ToString isn't an SQL function, therefore it can't be done within the SQL query.
Try this:
var query = (from i in Expenditure
join d in Department on i.DepartId equals d.dID
where i.Status == "Audit"
group i by new { i.InvoiceId, d.Title, i.InvoiceDate } into g
select new
{
g.Key.InvoiceId,
g.Key.Title,
g.Key.InvoiceDate,
}).ToList()
.select new
{
id = InvoiceId,
txt = Title + " // " + InvoiceId + " // " + Convert.ToString(InvoiceDate)
};
Everything after the .ToList() will be done in memory, where you can use any .NET method.
Instead of assembling txt in database and force Linq To Entities to transform your logic into SQL, first retrieve the data and then apply transformations
Try following
var query =
(from i in Expenditure
join d in Department on i.DepartId equals d.dID
where i.Status == "Audit"
group i by new { i.InvoiceId, d.Title, i.InvoiceDate } into g
select new
{
id = g.Key.InvoiceId,
title = g.Key.Title,
invoiceId = g.Key.InvoiceId,
invoiceDate = g.Key.InvoiceDate
})
.ToList()
.Select(it => new
{
id = it.id,
txt = it.title + " // " + it.invoiceId + " // " + it.invoiceDate
});

Linq To SQL toList<class> - Invalid Cast

I am not sure what I am doing wrong. But the linq to sql is choking when I do a toList.
it is running this area of the select.
case RightSearchType.Text:
If put the results in a var variable and not use the ToList it runs fine gets the results no problem.
I have tried
ToList()
ToList<URRightsView>()
Both of them yield the same issue.
I wish to pass back a strongly type List when developers call this method.
Please keep in mind this is not finished code. This is the first time I am using LINQ to SQL and my very first test to see if I am doing it right.
Thus failing badly.
Any help in resolving the casting problem is truly appreciated :)
public static List<URRightsView> Search(string SearchText, long Id, RightSearchType SearchType)
{
List<URRightsView> dRights = null;
try
{
using (DataContext db = new DataContext(AppSettings.Settings.ConnectionString))
{
Table<URRights> tRights = db.GetTable<URRights>();
Table<URRoles> tRoles = db.GetTable<URRoles>();
Table<URApps> tApps = db.GetTable<URApps>();
Table<URRightRoleMapping> tMapRoles = db.GetTable<URRightRoleMapping>();
Table<URApplicationRight> tMapApps = db.GetTable<URApplicationRight>();
string results = string.Empty;
switch (SearchType) {
case RightSearchType.Application:
dRights = (from ma in tMapApps
join apps in tApps on ma.AppFK equals apps.AppId
join r in tRights on ma.RightFK equals r.RightId
where (r.Title.Contains(SearchText) || r.Description.Contains(SearchText)) && ma.AppFK == Id
orderby r.Title, apps.Name ascending
select new URRightsView
{
Title = r.Title,
Classification = r.Classification,
Description = r.Description,
RightId = URUtil.GetLong(r.RightId),
RightType = r.RightType,
AppName = apps.Name
}).ToList<URRightsView>();
break;
case RightSearchType.Role:
dRights = (from ma in tMapApps
join apps in tApps on ma.AppFK equals apps.AppId
join r in tRights on ma.RightFK equals r.RightId
join mr in tMapRoles on r.RightId equals mr.RightFK
where (r.Title.Contains(SearchText) || r.Description.Contains(SearchText)) && ma.AppFK == Id
orderby r.Title, apps.Name ascending
select new URRightsView
{
Title = r.Title,
Classification = r.Classification,
Description = r.Description,
RightId = URUtil.GetLong(r.RightId),
RightType = r.RightType,
AppName = apps.Name
}).ToList<URRightsView>();
break;
case RightSearchType.Text:
dRights = (from ma in tMapApps
join apps in tApps on ma.AppFK equals apps.AppId
join r in tRights on ma.RightFK equals r.RightId
where r.Title.Contains(SearchText) || r.Description.Contains(SearchText)
orderby r.Title, apps.Name ascending
select new URRightsView
{
Title = URUtil.GetString(r.Title),
Classification = URUtil.GetString(r.Classification),
Description = URUtil.GetString(r.Description),
RightId = URUtil.GetLong(r.RightId),
RightType = URUtil.GetLong(r.RightType),
AppName = URUtil.GetString(apps.Name)
}).ToList<URRightsView>();
break;
}
}
}
catch (Exception ex)
{
URErrors.HandleError(ex, UserName);
JavaScriptSerializer serial = new JavaScriptSerializer();
string error = "URRights.Search Method: Could not Search Text - " + SearchText + ", SearchType = " + SearchType.ToString() + ",Id = " + Id.ToString() + Environment.NewLine;
URErrors.HandleError(ex, UserName);
throw new Exception(error);
}
return dRights;
}
UPDATE WITH EXCEPTION
Message
Specified cast is not valid.
at System.Data.SqlClient.SqlBuffer.get_Int64()
at System.Data.SqlClient.SqlDataReader.GetInt64(Int32 i)
at Read_URRightsView(ObjectMaterializer`1 )
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at URCore.URSecurity.URRights.Search(String SearchText, Int64 Id, RightSearchType SearchType) in D:\Development\Websites\unravelingspirit\URCore\URSecuirty\URRights.cs:line 244

One context reference LINQ query throws multiple references exception - BUG?

I'm using the following code:
using(MainEntities mainContext = new MainEntities())
{
return (from member in mainContext.aspnet_Membership
where adminGroupUserIDs.Contains(member.UserId)
select new
{
FullName = member.FirstName + " " + member.LastName,
UserName = (from user in mainContext.aspnet_Users
where user.UserId == member.UserId
select user.UserName)
}).ToList();
}
where adminGroupUserIDs is an IQueryable<GUID> that is formed from a query to a different instance of MainEntities.
With this query LINQ complains that:
The specified LINQ expression contains references to queries that are associated with different contexts.
Any ideas why?
I can't be certain from the code you show here, but I'm pretty sure that adminGroupUserIDs is the result of another query that hasn't been retrieved yet, and was created with a different instance of MainEntities. You can't mix queries from different contexts, not even different instances of the same context class. Try changing it to the following:
var loadedAdminGroupUserIDs = adminGroupUserID.ToArray();
using(MainEntities mainContext = new MainEntities())
{
return (from member in mainContext.aspnet_Membership
where loadedAdminGroupUserIDs.Contains(member.UserId)
select new
{
FullName = member.FirstName + " " + member.LastName,
UserName = (from user in mainContext.aspnet_Users
where user.UserId == member.UserId
select user.UserName)
}).ToList();
}
Try adding .FirstOrDefault() to your subquery.
using(MainEntities mainContext = new MainEntities())
{
return (from member in mainContext.aspnet_Membership
where adminGroupUserIDs.Contains(member.UserId)
select new
{
FullName = member.FirstName + " " + member.LastName,
UserName = (from user in mainContext.aspnet_Users
where user.UserId == member.UserId
select user.UserName).FirstOrDefault()
}).ToList();
}

Perform group and join using LINQ

Does anyone have any suggestions about how I might do this using just LINQ?
var statements = db.vwOutstandingStatements.ToList();
var amounts = (from s in db.vwOutstandingStatements
group s by s.Id into v
select new
{
Id = v.Key,
amount = v.Sum(a => a.Amount)
}).ToList();
List<vmVendorStatements> statementsToProcess = new List<vmVendorStatements>();
foreach (var amount in amounts)
{
var statement = statements.Find(s => s.Id == amount.Id);
statementsToProcess.Add(new vmVendorStatements()
{
Id = statement.Id,
PropertyAddress = statement.PropertyNumber + " " + statement.PropertyStreet + " " + statement.PropertyTown,
StatementDate = statement.StatementDate.ToLongDateString(),
Amount = amount.amount.ToString()
});
}
Statements is from a sql view via EF5. I run the LINQ to get the data grouped by the sum of the amounts in the returned view and then join it back to show some of the detail from the returned view along with the sums amounts. StatementsToView is my view model to get the data into an MVC view.
I'm sure it could be done in SQL, and I might do that in any case, but there also seems as though there must be a neater solution to the above too.
Thanks,
Jason.
You can just grab out the first item in the group rather than re-querying just to find the first item:
var statementsToProcess =
(from s in db.vwOutstandingStatements
group s by s.Id into v
let first = v.First()
select new vmVendorStatements()
{
Id = v.Key,
amount = v.Sum(a => a.Amount),
PropertyAddress = first.PropertyNumber + " " + first.PropertyStreet + " " + first.PropertyTown,
StatementDate = first.StatementDate.ToLongDateString(),
}).ToList();

return one string with multiple column value linq

I have a query.
Is it possible to return One string with multiple column value in linq ??
Like this
string ProductName = ((from P in DataModel.DIS_PRODUCT
join M in DataModel.SET_PACK_UNIT on P.PUNIT_ID equals M.ID
where P.PRODUCT_ID == ProdictId
select P.PRODUCT_NAME +" " + P.WEIGHT + " "+ M.UNIT_SYMBLE)
.Take(1)
).ToString();
You're using Take(1) which means you're still getting an IEnumerable<string> or an IQueryable<string>. Just use First() (or possibly FirstOrDefault()) instead of Take(1) and you can drop the ToString() call as well.
string productName = (from P in DataModel.DIS_PRODUCT
join M in DataModel.SET_PACK_UNIT
on P.PUNIT_ID equals M.ID
where P.PRODUCT_ID == ProdictId
select P.PRODUCT_NAME + " " + P.WEIGHT + " "+ M.UNIT_SYMBLE)
.FirstOrDefault();
That will only work if your LINQ provider supports the string concatenation operation. An alternative is to fetch just the columns you want, and then concatenate at the caller:
var query = from P in DataModel.DIS_PRODUCT
join M in DataModel.SET_PACK_UNIT
on P.PUNIT_ID equals M.ID
where P.PRODUCT_ID == ProdictId
select new { P.PRODUCT_NAME, P.WEIGHT, M.UNIT_SYMBLE };
var result = query.FirstOrDefault();
if (result != null)
{
string productName = result.PRODUCT_NAME + " " +
result.WEIGHT + " " +
result.UNIT_SYMBLE;
// Use the name
}
else
{
// No results
}
Another more clear way is the following
var ProductsQueryItem = (from p in Products
select new
{
Name = e.ProductName+ " " + e.weight +e.UNIT_SYMBLE
})
.FirstOrDefault();
Now you can use it directly with ProductsQueryItem .Name

Categories