Linq query expression - c#

I am writing a join query that produces an anonymous result set. My problem is that I don't know which data type should be returned from my function service and I tried to return object type but I don't know how to access the elements of result in my source code...
Here is my code:
public static IEnumerable<object> GetProductSalesInfoById(int id)
{
var query = from product in database.Products
join sales in database.SalesOrderDetails
on product.ProductID equals sales.ProductID
select new {Name = product.Name,OrderId = sales.SalesOrderID,TotalPrice = (sales.UnitPriceDiscount)*sales.OrderQty*sales.UnitPrice};
IEnumerable<object> result = query.ToList();
return result;
}

You should create a DTO class that contains the properties in your anonymous object and return an IEnumerable<T> of it. Another not so good solution is to use dynamic but I wouldn't use that.

crate one custom class like this
public partial class ResultClass
{
public string Name {get;set;}
public int OrderId {get;set;}
public double TotalPrice {get;set;}
}
public List<ResultClass> GetProductSalesInfoById(int id)
{
var query = from product in database.Products
join sales in database.SalesOrderDetails
on product.ProductID equals sales.ProductID
select new ResultClass {Name = product.Name,OrderId = sales.SalesOrderID,TotalPrice = (sales.UnitPriceDiscount)*sales.OrderQty*sales.UnitPrice};
return result.ToList();
}
hope this will help you out.

You can use Tuple or anonymous type(you need to use casting to get back the object).
Check this link for usage : Anonymous & tuple objects

Related

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
}

How to cast back an object with a linq query inside it with more than 1 entity? [duplicate]

This question already has answers here:
How to return query results from method that uses LINQ to SQL
(7 answers)
Closed 9 years ago.
I have the following scenario. One linq query with a join statment:
public Object getMGM(int MEB_Id)
{
var unitOfWork = new DAL.Implementations.Entity_Framework.UnitOfWork<dbgmEntities>();
var queryRoles = from a in unitOfWork._ctx.MembrosMGM
join b in unitOfWork._ctx.Membros on a.MGM_Pai equals b.MEB_Id
where a.MGM_Filho == MEB_Id
select new { b.MEB_Nome, b.MEB_Id, a.MGM_Familiar };
return queryRoles;
}
queryRoles is running inside a thread. So, I only have to return it as an object. But I cannot find a way to cast it and get the { b.MEB_Nome, b.MEB_Id, a.MGM_Familiar } of the select. I tried the following code with one Entity set on the return and it works fine, but if I have more than 1 entity on the same linq query i don't know how to cast it back:
//this one works fine if i have just one entity set (DAL.MembroResponsavel)
var queryMembroResponsaveis = ((IEnumerable)smartThreadPool.QueueWorkItem(x => editMeb.getMembroResponsavel(currentId)).Result).Cast<DAL.MembroResponsavel>().ToList();
Thanks.
For those having the same problem returning an Anonymous Type I created a class that gets its return values:
public class MemberGetaMember
{
public int MEB_Id {get;set;}
public string MEB_Nome { get; set;}
public bool? MGM_Familiar { get; set; }
}
Then i can cast it back on the return:
foreach (var x in queryRoles)
list.Add(new MemberGetaMember { MEB_Id = x.MEB_Id, MEB_Nome = x.MEB_Nome, MGM_Familiar = x.MGM_Familiar });
return list;
This question helped me how to figure this out
How to return query results from method that uses LINQ to SQL
Thanks everyone.
I suspect you need to enumerate the results and cast to a list:
var queryRoles = (from a in unitOfWork._ctx.MembrosMGM
join b in unitOfWork._ctx.Membros on a.MGM_Pai equals b.MEB_Id
where a.MGM_Filho == MEB_Id
select new { b.MEB_Nome, b.MEB_Id, a.MGM_Familiar }).ToList();

Computed Columns in EF using LINQ

With the following code;
using (var context = new FINSAT613Entities())
{
gridControl1.ForceInitialize();
DateTime endtime= new DateTime(2013, 03, 29, 15, 49, 54);
Text = "endtime:"+endtime.ToShortDateString();
var query =
from A in context.A
join B in context.B on A.ID equals B.ID
join C in context.C on A.ID2 equals C.ID2
where A.endtime> endtime && A.Chk.StartsWith("320")
select new
{
A.ID,B.FOO,C.BAR etc...
};
BindingSource.DataSource = query;
gridControl1.DataSource = BindingSource;
}
How can i add computed columns to it?(multiples a.bar with b.foo for example)
Tried using partial class but no luck with it.
public partial class A
{
public decimal Calculated
{
get { return 15; }
}
}
The exact error i get is :
{"The specified type member 'Computed' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."}
You can create class, wich has got all the fields you need: id, foo, bar, etc. and add to it Calculated field, then just modify your query:
var query =
from A in context.A
join B in context.B on A.ID equals B.ID
join C in context.C on A.ID2 equals C.ID2
where A.endtime> endtime && A.Chk.StartsWith("320")
select new YourNewClass
{
Foo = A.foo,
Bar = B.bar,
... ,
Calculated = A.foo * B.bar
};
EDITED: if you have got a lot of fields, you can use automapper
Here is an example. Say, you have got class User from your DB and you have got class UserModel, in which you added a field FullName which constist from fields Name and Surname. So you want to create an object UserModel from object User but not to copy all the fields exclicitly. That's how you can do it:
class Program
{
static void Main(string[] args)
{
User u = new User { Name = "My", Surname = "Name" };
Mapper.CreateMap<User, UserModel>().ForMember(dest => dest.FullName, o => o.MapFrom(src => string.Format("{0} {1}", src.Name, src.Surname)));
UserModel um = Mapper.Map<User, UserModel>(u);
Console.WriteLine(um.FullName);
}
}
public class User
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class UserModel
{
public string Name { get; set; }
public string Surname { get; set; }
public string FullName { get; set; }
}
Did you solve this?
I've been looking for a neater way myself,
I don't like using ViewModels when all I want to add to an existing model is only one or two pieces of additional info.
What I tend to do is create have a non mapped field in my model, get all the info I need from the LINQ into a temporary model and then perform any required remapping in another loop before I send it back to the client.
So for example;
public partial class A
{
[NotMapped]
public decimal Calculated {get;set;}
}
then in my Linq Query
var query =
from A in context.A
join B in context.B on A.ID equals B.ID
join C in context.C on A.ID2 equals C.ID2
where A.endtime> endtime && A.Chk.StartsWith("320")
select new
{
A = A,
B = B,
C = C
};
foreach(item i in query)
{
A.Calculated = A.Foo * B.Bar;
}
return query
OK, it means another loop, but at least it's only one DB call.
Another option would be to do it all in T-SQL and issues the T-SQL directly (or via a stored proc)
this link explains how - as an added bonus this method is much faster with more complex queries, but it always feels like a bit of a hack to me.
http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx
I accomplished this by putting my data into a List first. This is probably terrible (especially if you have a large amount of results) but it does work and is easy to understand.
There's a loop involved going through the whole list. I'm not sure if other solutions require this but I also am currently having a hard time understanding them, so I need something that works for what I was trying to do, which was to populate a DropDownList.
Again I really don't think this solution is ideal:
Let's say I have an entity YourEntities with a table Registration
using (var context = new YourEntities())
{
var query = from x in context.Registrations
select x; //Just an example, selecting everything.
List<Registration> MyList = query.ToList();
foreach (Registration reg in MyList) //Can also be "var reg in MyList"
{
MyDropDownList.Items.Add(new ListItem(reg.LastName + ", " + reg.FirstName, reg.ID));
//Or do whatever you want to each List Item
}
}

Using LINQ, select list of objects inside another list of objects

public class ClassA
{
public string MyString {get; set;}
}
public class ClassB
{
public List<ClassA> MyObjects {get; set;}
}
List<ClassB> classBList = new List<ClassB>();
var results = (from i in classBList select i.MyObjects).Distinct();
I want a distinct list of all the ClassA objects in the classBList. How do I go about this using LINQ? I'm thinking about a nested query, but couldn't quite figure it out. Any help is very appreciated.
You're trying to select multiple result objects for each ClassB object in the original list.
Therefore, you're looking for the SelectMany extension method:
var results = classBList.SelectMany(b => b.MyObjects).Distinct();
If you want to use query expressions, you'll need to use two from clauses:
var results = (from b in classBList from a in b.MyObjects select a).Distinct();
You want to use IEnumerable.SelectMany() Extension Method to flatten the hierarchy:
var result = classBList.SelectMany(b => b.MyObjects).Distinct();

how to convert multiple linq statement to selectmany

I am a beginner with LINQ and lambda function's. I was wondering how can i convert multiple linq statement to one statement using selectmany function.
string viewname = (from a in StoredProcedureParameters.Tables[0].AsEnumerable()
where a.Field<string>("ViewName") == displayName
select a.Field<string>("View")).Single();
DateTime date = (from d in StoredProcedureParameters.Tables[0].AsEnumerable()
select d.Field<DateTime>("Date")).First();
Thanks for help in advance.
If you want a single query, you could have the select value be an anonymous type. But the scope of the return value is the method where the type is created.
var result = (from a in StoredProcedureParameters.Tables[0].AsEnumerable()
where a.Field<string>("ViewName") == displayName
select new { View = a.Field<string>("View"),
Date = d.Field<DateTime>("Date") }).Single();
then the variable result will be an object with the properties 'View' and 'Date'. You can't return this value from a method though. If you need to return the value, you could create a simple class
public class ViewDate
{
public string View { get; set; }
public DateTime Date { get; set; }
}
Then using an object initializer, you will end up with result containing an instance of the ViewDate object, which you can return from your method.
var result = (from a in StoredProcedureParameters.Tables[0].AsEnumerable()
where a.Field<string>("ViewName") == displayName
select new ViewDate() { View = a.Field<string>("View"),
Date = d.Field<DateTime>("Date") }).Single();
I don't think SelectMany does what you think it does. It's usually just a flatten operation. Why do you think it would help you in this case? Why do you want to avoid two queries?

Categories