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
}
Related
I need to return one row of List from my function Selectus.
So I pass to the function Selectus object that reflects database table fields and I need to return one row which match the parameter looking_for:
public static List<T> Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.ToList();//here one record should be returned
}
I do not know how to select one row from the list assuming that T parameter is vary. In SelectusT> method I want to pass as T different objects which reflect fields in database table rather than creatinig separate methods for each select. e.g. call Selectus, where object passed is public class ProductCodes { public int ID { get; set; } public string SapIndex { get; set; } public string SapName { get; set; } }. Then I want to call another Selectus<ProductTypes> for another table etc... So I want to write generic/overall method and use it universally for all types of my objects which reflects the fields of few database tables. The SapIndex property is always in the same place of all objects...
Using prop[1] is incredibly fragile. Who says that the property you're currently interested in is always going to be in second place? What if someone adds another property tomorrow? What if not every T that you use have the same property in the second place on its list of properties? It is quite unclear what your actual goal is here and why you've taken the reflection route.
You would be better off using inheritance or interface implementation here. I'm going to use an interface in this answer, but either would work.
For the sake of clarity, let's assume there is a Code field in all your possible lists, and this is the property you're trying to match with.
Define a reusable interface:
public interface ICodeEntity
{
string Code { get; }
}
Apply your interface to all of the classes that you intend to use for your Selectus method.
public class Person : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
public class Document : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
Add a generic type constraint that limits the use of T only to types that implement your interface.
public static List<T> Selectus<T>(string code)
where T : ICodeEntity
You can now write your code in a way that it relies on the type in question having a Code property, and the compiler will help enforce it.
var db = OrmLiteBaza().Open();
var list = db.Select<T>().ToList();
db.Dispose();
return list.Where(item => item.Code == code).ToList();
Usage examples:
List<Person> peopleWithCodeABC = Selectus<Person>("ABC");
List<Person> documentsWithCodeXYZ = Selectus<Document>("XYZ");
// This will fail if Animal does not implement ICodeEntity
var compilerError = Selectus<Animal>("ABC");
I might not understand fully what you want, but instead of string looking_for you could pass in a Func<,> delegate which acts as a selector.
Something like:
public static List<TField> Selectus<T, TField>(Func<T, TField> selector)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Select(selector); // 'using System.Linq;'
return list_selected_record.ToList();
}
Then I believe it could be called like this:
var list_one = Selectus((ProductCodes x) => x.SapIndex);
var list_two = Selectus((ProductTypes x) => x.SapIndex);
var list_three = Selectus((ProductCodes x) => x.SapName);
With this syntax I leave out the <ProductCodes, string> generic arguments to the method since they can be inferred.
Hmm, maybe you want it in the opposite dimension. You could do:
public static List<T> Selectus<T>(Func<T, bool> predicate)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Where(predicate); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus((ProductCodes x) => x.SapIndex == "ABC");
var list_two = Selectus((ProductTypes x) => x.SapIndex == "ABC");
var list_three = Selectus((ProductCodes x) => x.SapName == "DaName");
or:
var list_one = Selectus<ProductCodes>(x => x.SapIndex == "ABC");
var list_two = Selectus<ProductTypes>(x => x.SapIndex == "ABC");
var list_three = Selectus<ProductCodes>(x => x.SapName == "DaName");
But if it is going to always be the "same" property, like always x.SapIndex (but for different types of x), then Flater's answer looks good.
Otherwise, if you insist, your reflection approach should be possible. Use propety's name, not its index! Let me try:
public static List<T> Selectus<T>(string looking_for)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
const string prop_name = "SapIndex";
var prop = typeof(T).GetProperty(prop_name); // can blow up for bad T
var list_selected_record = select_all_list
.Where(x => (string)(prop.GetValue(x)) == looking_for); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus<ProductCodes>("ABC");
var list_two = Selectus<ProductTypes>("ABC");
you can change code to return just one element
public static T Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.FirstOrDefault();//here one record should be returned
}
This question already has answers here:
Returning anonymous type in C#
(16 answers)
Closed 4 years ago.
The details of the linq expression are not important except for the fact that it creates a new unnamed object:
select new { ... }
Thus I have no return type for the function. There has to be a generic untyped type like Javascript's "any".
public ??? Get(int id)
{
var hisGrade = (from p in ctx.Students
where p.StudentID == id
select new { area = p.Grade.Section, name = p.Grade.GradeName }).FirstOrDefault();
return hisGrade;
}
Every example I find just shows the code without the enclosing function!
Thanks for your help.
Chuck
You can return dynamic, it will declare a type in run-time with two properties: area and name:
public dynamic Get(int id)
{
var hisGrade = (from p in ctx.Students
where p.StudentID == id
select new { area = p.Grade.Section, name = p.Grade.GradeName }).FirstOrDefault();
return hisGrade;
}
Thus you can access the members of the object returned, but you will miss the IntelliSense and the type-checking at compile-time:
var name = Get(1).name;
Are you assuming it would always have to be an anonymous type that is returned by a Select call? You would be wrong.
public struct MyType
{
public string Area { get; set; }
public string Name { get; set; }
}
class Class1
{
public MyType Get(int id)
{
var hisGrade = (from p in ctx.Students
where p.StudentID == id
select new MyType{ Area = p.Grade.Section, Name = p.Grade.GradeName }).FirstOrDefault();
return hisGrade;
}
}
I have 2 repositories, Member and Person. The Person Model contains a nullable reference property to a Member Model. The Member Model is defined in the Member Repository and I would like to put in place a pattern that ensures this stays that way. however, when I call the methods in the member repo from the person repo I get the
LINQ to Entities does not recognize the method 'System.Linq.IQueryable 1[...IMember] Get(..Entities,System.Linq.Expressions.Expression 1[System.Func`2[..tblMember,System.Boolean]])' method, and this method cannot be translated into a store expression."
While I understand this can be easily solved by putting .asEnumerable() then a second select there is a cost that means your doing 2 queries instead of one and you loose the ability to expose the method as awaitable. Below is the code I have removed a few non essential parts to clearify. I am not using lambda because I have not found a good way to say let in a lambda expression. My goal is person.Member would simply be a nested select. Also Note that the Member side of things is a very ugly database that I have not control over and these repos are being separated for a reason. Thanks in advance
public class MemberRepository : Interfaces.IRepository<IMemberBase, string>
{
private Data.LSAEntities entities { get; set; }
public MemberRepository(Data.LSAEntities entities)
{
this.entities = entities;
}
internal static IQueryable<IMember> Get(Data.LSAEntities entities, Expression<Func<tblMember, bool>> predicate)
{
return (from t in entities.tblMembers.Where(predicate)
let options = entities.tblDataOptions.Where(o => o.DataName == "MemberStatus")
select new Member()
{
MemberID = t.MemberID,
...
});
}
}
public class PersonRepository : IRepository<IPerson, int>
{
private Data.LSAEntities entities { get; set; }
public PersonRepository(Data.LSAEntities entities)
{
this.entities = entities;
}
public IQueryable<IPerson> Get(int key)
{
return (from p in entities.tblPersons
where p.PersonId == key
select new Person()
{
PersonId = p.PersonId,
...
Member = MemberRepository.Get(entities, m=> p.MemberId == m.MemberID).FirstOrDefault()
});
}
}
This may help you:
Given
var ans = from a in table
let b = a.TotalPrice / a.Quantity
where b > 500
select new {
PriceEa = b,
a.ID,
a.Description
};
translates to
var ans = table.Select(a => new { b = a.TotalPrice / a.Quantity, a })
.Where(ba => ba.b > 500)
.Select(ba => new {
PriceEa = ba.b,
ba.a.ID,
ba.a.Description
});
the let clause in query comprehension syntax in LINQ is translated to a Select adding a new field to hold the let value when using lambda syntax.
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
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
}
}