Cannot serialize interface System.Linq.IQueryable - c#

I'm faced with an error, "Cannot serialize interface System.Linq.IQueryable." when I try to run my method in my web service. My class is as such:
public class AirlineSearchStrong
{
public Flight_Schedule flightSchedule { get; set; }
public Flight_Schedule_Seats_and_Price flightScheduleAndPrices { get; set; }
public Airline airline { get; set; }
public Travel_Class_Capacity travelClassCapacity { get; set; }
}
[WebMethod]
public IQueryable SearchFlight(string dep_Date, string dep_Airport, string arr_Airport, int no_Of_Seats)
{
AirlineLinqDataContext db = new AirlineLinqDataContext();
var query = (from fs in db.Flight_Schedules
join fssp in db.Flight_Schedule_Seats_and_Prices on fs.flight_number equals fssp.flight_number
join al in db.Airlines on fs.airline_code equals al.airline_code
join altc in db.Travel_Class_Capacities on al.aircraft_type_code equals altc.aircraft_type_code
where fs.departure_date == Convert.ToDateTime(dep_Date)
where fs.origin_airport_code == dep_Airport
where fs.destination_airport_code == arr_Airport
where altc.seat_capacity - fssp.seats_taken >= no_Of_Seats
select new AirlineSearchStrong {
flightSchedule = fs,
flightScheduleAndPrices = fssp,
airline = al,
travelClassCapacity = altc
});
return query;
}
I've tried IQueryable, IList and returning .ToList() but most of it has turned out to be unsuccessful

i dont think
you can use Iqueryable or Ienumerable as they both do lazy execution and are not serializable. The query gets executed only when you iterate through the collection.so it doesn't make sense to return the query to the caller and asking him to iterate as his end.you need to pass a List or an Array.
You may need to change the return type to List<Type>

Hows about
public IEnumerable<AirlineSearchStrong> SearchFlight(string dep_Date, string dep_Airport, string arr_Airport, int no_Of_Seats)
{
...
return query.ToList();
}
Your trying to serialize a representation of the data, the linq query itself, instead of the data resulting from executing the query, thats why it isnt working.
You need to enumerate the linq query into an enumerable set, and serialize that.
AirlineSearchStrong might need to be marked [Serializable()]

Related

Update model sort order [duplicate]

Any idea why the LINQ OrderBy is not working in following code, (have no errors but method does not sort ...)
First my own type
public class IQLinksView
{
public int id { get; set; }
public int catid { get; set; }
public int? viewed {get;set;}
public string name {get;set;}
public string desc {get;set;}
public string url {get;set;}
public string pic {get;set;}
public string cat {get;set;}
}
then query :
IQueryable<IQLinksView> newView =
from links in this.emContext.tbl_otherlinks
select new IQLinksView { id = links.pklinkid, catid =
links.tbl_catgeory.pkcategoryid, viewed = links.linkviewed, name = links.linkname,
desc = links.linkdesc, pic = links.linkpicture, url = links.linkurl, cat =
links.tbl_catgeory.categoryname };
Untill here all fine :-), but then
newView.OrderBy(x => x.viewed);
just changes nothing,... Page is loading results showing ... but no ordering ... sniff
i have Try with (creating a comparer object ... ):
newView.OrderBy(x => (Int32)x.viewed, new CompareIntegers());
same result, no ordering ...
I do have workarounds but just wondering what is missing ....
Any suggestions will be appreciated thanks a lot :-)
Don't throw away the return value. The OrderBy extension method is does not mutate the input. Try:
newView = newView.OrderBy(x => x.viewed);
There is no reason why that won't work, assuming the viewed value is correct. Also, make sure that OrderBy is after any operations (e.g. Distinct) which will ruin ordering.
Happy coding!
No-Tracking Queries
Consider use the asnotracking() after orderby() if the result is a readonly result.
Example:
query = query.OrderByDescending(x => x.Rating).AsNoTracking();

How to use a copy-constructor in a LINQ to Entities query?

I'm working on a Linq expression in which I get an object from a DBContext, and I want to make it a custom ViewModel object
my ViewModel receives as parameter an object obtained from the DBContext to work the information and return it completely
This is a little example
public class Obj1 // Object i get from database
{
public int id { get; set; }
public string Param { get; set; }
public string Param2 { get; set; }
public string Random { get; set; }
}
public class Obj2 //ViewModel
{
public string ParamFormateado { get; set; }
public string Random { get; set; }
public Obj2(Obj1 parametro)
{
ParamFormateado = parametro.Param + parametro.Param2;
Random = parametro.Random;
}
}
What I'm trying to do is get an Obj2 with a Linq expression who returns an Obj1 without transforming the information in the linq expression, since in my case it becomes a basically illegible expression
I was try something like this
Obj2 objeto = db.Obj1.Where(x => x.id == "0").Select(x => new Obj2(x)).FirstOrDefault();
Is it possible to perform a Linq query similar to the one I am proposing? since otherwise, I end up having extremely long Linq expressions to format this information, but what would be the best alternative in these cases?
You can't do that because only parameterless constructors are supported. But you can do it with Linq-To-Objects which can be forced with AsEnumerable:
Obj2 objeto = db.Obj1
.Where(x => x.id == "0")
.AsEnumerable() // <--- here
.Select(x => new Obj2(x))
.FirstOrDefault();
So only the filter with Where will be executed in the database, the remaining record(s) are processed in-process.
https://codeblog.jonskeet.uk/2011/01/14/reimplementing-linq-to-objects-part-36-asenumerable/
Dont do it with Linq like that. you have to create a method that takes obj1 as parameter, maps properties and then returns obj2. Or use Automapper from nuget repository.
do it like this
public obj2 Map(obj1 source)
{
var destination = new obj2();
destination.param1 = source.param1;
//
return destination;
}
if you want to pass a collection of objects then do just that and just foreach through the list and return a list of mapped objects. But i would advise you to use Automapper since it automates the proces and you dont have to write a long mapping code.

Covariance and orderby() issue

Consider below code
public class CommentBll : IBaseBllPersistor<Comment>
{
public List<Comment> GetData<TProp>(Expression<Func<Comment, TProp>> selector)
{
using (var context = new WebsiteContext())
{
var query = (from q in context.Comment
select new CommentDto
{
ExtraProp = q.Name+q.Id.ToString(),
PostDate = q.PostDate,
}).OrderBy(selector);
return query.ToList();
}
}
public class CommentDto: Comment
{
public string ExtraProp { get; set; }
}
}
public class Comment: IBaseModel
{
public string CommentText { get; set; }
public DateTime PostDate { get; set; }
}
When I remove this part from end of query
OrderBy(selector)
I get this error,
Error CS0029 Cannot implicitly convert type System.Collections.Generic.List<CommentDto> to System.Collections.Generic.List<Comment>
I know about covariance and I know the error is about it but why when I add OrderBy(selector) the error disappears?
Any ideas why this might be happening?
Any ideas why this might be happening?
It's not so hard to be explained.
Let split your query in two parts:
var queryA = (from q in context.Comment
select new CommentDto
{
ExtraProp = q.Name+q.Id.ToString(),
PostDate = q.PostDate,
});
var query = queryA.OrderBy(selector);
The type of queryA is IQueryable<CommentDto>.
Now, the type of the first generic argument of the selector is Comment. Since the IQueryable<T> is covariant and Expression<TDelegate> is invariant, the only way the compiler can satisfy your second query is to threat queryA as IQueryable<Comment>, hense the type of query is IOrderedQueryable<Comment>, and the final ToList call produces List<Comment>.
Apparently w/o the OrderBy you are calling ToList on queryA and the result is List<CommentDto>.
In the later case, the covariance of the IQueryable<T> allows easily getting the desired result by simply specifying explicitly the generic argument for the ToList call:
return queryA.ToList<Comment>();
Specify the return type Comment with the ToList() as mentioned below
return query.ToList<Comment>();

How to return LINQ object from method?

I have method which has LINQ query and query return columns from multiple tables.
How can I return that LINQ results object and catch it in caller method iterate results and assign to model class?
public ??? GetLocation(string CustomerNum)
{
if (!string.IsNullOrEmpty(CustomerNum))
{
var results = from ca in _context.CUS_ADDRESS
join cad in _context.CUS_ADDRESS_DETAIL on ca.CUS_ADDRESS_ID equals cad.CUS_ADDRESS_ID
where (cad.PRIORITY_SEQ == 0) && (ca.MASTER_CUSTOMER_ID == CustomerNum)
select new
{
CustomerNumber = ca.MASTER_CUSTOMER_ID,
ca.ADDRESS_1,
ca.ADDRESS_2,
ca.ADDRESS_3,
ca.ADDRESS_4,
ca.CITY,
ca.STATE,
ca.COUNTRY_DESCR,
cad.ADDRESS_TYPE_CODE,
cad.ADDRESS_STATUS_CODE
};
return results;
}
else
{
return null;
}
}
Caller method
var results = Data.GetLocation(CustomerNum)
if (results.Any())
{
var location = results.FirstOrDefault();
.....
.....
}
What will be the GetLocation return type?
Depending on how you are actually using the results, you could return an IQueryable instead of IQueryable<T>.
I've used this in some situations (using IEnumerable), like WebForms, that have dynamic binding (either through Eval or by using a BoundField for instance.
You are creating an anonymous object with select new, you can't return a collection of anonymous object from your function, instead you have to create a class which would have all the properties from your select statement and then return IQueryable<YourClass>
class YourClass
{
public int CustomerNumber { get; set; }
public string ADDRESS_1 { get; set; }
//..............
}
and then :
var results = from ca in _context.CUS_ADDRESS
join cad in _context.CUS_ADDRESS_DETAIL on ca.CUS_ADDRESS_ID equals cad.CUS_ADDRESS_ID
where (cad.PRIORITY_SEQ == 0) && (ca.MASTER_CUSTOMER_ID == CustomerNum)
select new YourClass
{
CustomerNumber = ca.MASTER_CUSTOMER_ID,
ADDRESS_1 = ca.ADDRESS_1,
//...............
And modify your function return type as:
public IQueryable<YourClass> GetLocation(string CustomerNum)
You can look at this question for returning IQueryable or Not
If you didn't feel like creating a class you could use Tuples:
public IEnumerable<Tuple<int, string, string>> GetCustomer(int custId) {
return from p in customers
where p.Id == custId
select new Tuple<int, string, string>(
p.Id,
p.FirstName,
p.LastName
);
}
Though this means that you can't name their fields since you access the data like this:
var customer = GetCustomer(1);
var custId = customer.Item1;
var custFirstName = customer.Item2;
var custLastName = customer.Item3;
Create a custom helper class having all columns as properties. Say its MyClass. Fill this as below. I know this not exactly what you want but will help you to get what you want.
var o= (from c in context.table1
from d in context.table2
where c.key=d.key
select new MyClass
{
Property1=c.abc,
Property2=d.xyz
}).SingleOrDefault();
Or write your joins and where in such a way that it will give you only single row fron db.
In the function you are creating an anonymous object and hence cannot be used in caller without some methods of reflection. But it will be much easier to return an object like
public class CustomerLocation
{
public string CustomerNumber {get; set;}
// and so on
}
which will can be placed in a common layer and accessed by both caller and sender and use properties explicitly.
For this your function is better be
public IQueryable<CustomerLocation> GetLocation(string CustomerNum)
{
// your code here
}

Chain Lambda Linq

public class Translation
{
public string LanguageCode { get; set; }
public string Value { get; set; }
}
public class tblEnumJobFunction
{
public string strEnum { get; set; }
public List<Translation> mlgValue { get; set; } //mlgValue->MultiLingualValue
}
I have a List<tblEnumJobFunction> JobFunctionList with some data.
Example Data:
JobFunctionList[0].strEnum="ENUM_Manager";
JobFunctionList[0].mlgValue[0].LanguageCode ="EN";
JobFunctionList[0].mlgValue[0].Value="Manager";
JobFunctionList[0].mlgValue[1].LanguageCode ="DE";
JobFunctionList[0].mlgValue[1].Value="Geschäftsführer";
JobFunctionList[1].strEnum="ENUM_Student";
JobFunctionList[1].mlgValue[0].LanguageCode ="EN";
JobFunctionList[1].mlgValue[0].Value="Student";
JobFunctionList[1].mlgValue[1].LanguageCode ="DE";
JobFunctionList[1].mlgValue[1].Value="Schüler";
I can filter this list with LINQ by given country Code and happy with it.
The Question is how can I write equivalent below query syntax by lambda with the List/Collection extensions?
It is a cascade/chain query; looking into a list that is inside another list.
This query syntax is working OK.
string CountryCode ="EN";
var Query = from jobfunction in JobFunctionList
from translation in jobfunction.mlgValue
where translation.LanguageCode == CountryCode //'EN'
select translation;
The Result is;
List<string> JobList;
foreach (var translationitem in Query)
{
JobList.Add(translationitem .Value);
}
now I have
JobList[0]="Manager";
JobList[1]="Student";
For CountryCode="DE" I have;
JobList[0]="Geschäftsführer";
JobList[1]="Schüler";
Is there any way to write above query syntax with lambda similiar to this one?
JobFunctionList.Select(a=>a.mlgValue).Where(b=>b....)...
Two from clauses, as in your example, flatten your sequence. You need to use SelectMany extension method. This is probably what you are looking for:
List<string> JobList = Objs.SelectMany(jobFunction => jobFunction.mlgValue)
.Where(translation => translation.LanguageCode == CountryCode)
.Select(translation => translation.Value)
.ToList();
note: consider using good names, even for formal parameters with the small scope within lambdas . a, b, m, fo are not the best names for this.

Categories