I'm using EF Code First (hybrid, database generation disabled) and I have two models/tables. I'm try to select and return all values in T1 and one field in a reference/lookup table so I can perform filtering on the list without requerying the database. I need to have the value of ItemName available so I can do comparisons.
If I were using SQL I'd just do something like this:
SELECT s.*, im.ItemName
FROM Specs s
INNER JOIN ItemMake im ON s.ItemMakeID = im.ID
My classes look something like this:
public class Spec {
public int ID {get; set;}
public int ItemMakeID {get; set;}
[ForeignKey("ItemMakeID")]
public ItemMake itemMake {get; set;}
}
public class ItemMake {
public int ID {get; set;}
public string ItemName {get; set;}
}
Currently my Linq to EF query looks like this. It doesn't work. I can't get at the ItemName property like I need to.
var specs = (from s in db.Specs
join im in db.ItemMakes on s.ItemMakeID equals im.ID
orderby s.modelNo select s).ToList();
What am I doing wrong?
That's because you're selecting just s in select clause. Use anonymous type declaration to get ItemName too:
var specs = (from s in db.Specs
join im in db.ItemMakes on s.ItemMakeID equals im.ID
orderby s.modelNo select new { s, im.ItemName }).ToList();
Related
I need to get data from SQL Server to my data grid view in Winforms
SELECT
Managements.OrderID, Managements.BookReturnDate, Managements.Money,
Books.bookName
FROM
Managements
INNER JOIN
Users ON Users.UserID = Managements.Username_UserID
INNER JOIN
Books ON Books.bookID = Managements.Book_bookID
How can I convert the query above to a code for Entity Framework?
Use linq
var s = from management in dbContext.Managements
join user in dbContext.Users on users.UserId equals management.Username_UserID
join book in dbContext.Books on book.BookId equals management.Book_bookID
select management.OrderID, management.BookReturnDate, management.Money,
book.bookName
As far as I can see Management table has one to many with User and Book tables.
If that is the case you can add, properties to the Management model in code and include these tables when you pull data from SQL Management table.
public class Management{
public int ManagmentId { get; set; }
public int UserId { get; set;}
public List<User> Users { get; set;}
public int BookId { get; set;}
public List<Book> Books { get; set;}
}
This should be your Management class.
For the query in Entity Framework try something like this:
public Managment GetData(int managmentId){
var data = context.Management
.Include(u => u.Users)
.Include(b => b.Books)
.FirstOrDefault(m => m.Id == managmentId);
}
I am writing an entity framework query that maps to a complex object of objects. I am using jquery datatables which passes over the query sort dynamically as a string typical like "item_id" or "item_id DESC". When passed into a SoryBy clause, it sorts the database results be the item id column. This is fine if that is the base object, but if I have a wrapper object which contains the object, it says item id is not defined for type ItemInfo.
A mockup of the classes are as follows.
public class Item {
public int item_id { get; set; }
public int category_id { get; set; }
}
public class ItemCategory {
public String category { get; set; }
public int category_id { get; set; }
}
public class ItemInfo {
public Item item { get; set; }
public ItemCategory category { get; set; }
}
What does the string for the .SortBy clause need to be to get the item_id from Item in an ItemInfo query?
IQueryable<ItemInfo> query = (from i in Item
join c in ItemCategory on i.category_id equals c.category_id
select new ItemInfo() {
item = i,
category = c
};
Simpler scenario with pure Linq:
If your scenario is simpler and you don't need dynamic at all, you can just do like this:
query = query.OrderBy(i => i.item.item_id);
// OR
query = query.OrderByDescending(i => i.item.item_id);
..which would use the property itself.
Dynamic scenario with "Dynamic Linq"
If you really needed dynamic (which means you would have to order by any fields and didn't want to put a lot of ifs in your code), then you would need to install this package System.Linq.Dynamic by running this in the Package Manager Console:
Install-Package System.Linq.Dynamic
Then you add this using clause:
using System.Linq.Dynamic;
Then you can achieve dynamic ordering with the following:
query = query.OrderBy("item.item_id DESC"); // keep the IQueryable
// OR
var items = query.OrderBy("item.item_id DESC").ToList(); // order in database...
When using this dynamic library, there is no OrderByDescending, since you can pass ASC or DESC with the string passed to the OrderBy() method (as in my example).
Take note item is the same name of the property inside ItemInfo. Also, ToList() is just an example, actually you don't need it at all, depending on your scenario.
Although I'd suggest you to change your ItemInfo to be like this:
public class ItemInfo {
public int item_id { get; set; }
public int category_id { get; set; }
}
...then fix your query to populate accordingly:
IQueryable<ItemInfo> query = (from i in Item
join c in ItemCategory on i.category_id equals c.category_id
select new ItemInfo() {
item_id = i.item_id,
category_id = c.category_id
};
query.OrderBy("item_id DESC");
This looks simpler and cleaner in my point of view. I'd avoid to put the whole object inside ItemInfo, keeping there exactly the properties you need, so you wouldn't load all the fields unnecessarily from database every time.
Suppose that I have list of following objects
public class OrderInfo
{
public string OrderNo {get; set;}
public DateTime OrderDate {get; set;}
public decimal OrderAmount {get; set;}
public decimal OrderPrice {get; set;}
}
as
List<OrderInfo> data = new List<OrderInfo>();
and this list has necessary number of items in it.
I need to select distinct OrderNo, OrderDate pairs from this List. In Linq I can write a query as:
var q = (from x in data
group x by new { x.OrderNo, x.OrderDate }
into grp
select new
{
grp.Key.OrderNo,
grp.Key.OrderDate
}).Distinct();
The thing is that I am writing a generic method so the object type and properties are unknown. So I have to write this with DLinq.
If I have a list of List<T> and a string[] { "OrderNo", "OrderDate" } how can I apply this example with DLinq at the run-time?
It was my fault. I was Googling for "DLinq" but not "Dynamic LinQ". Actually the answer was quite simple :
var q = data.Select("new (OrderNo, OrderDate)").Distinct();
I'm trying to order a list of "parent" items based on a value in its sub-collection's sub-collection. Here's the specifics...
I have a Film entity (mapped to the Films table) that has a one-to-many collection of Release entities (mapped to the Releases table). Each Release has one or more ReleaseDate entities (mapped to the ReleaseDates table).
public class Film {
public int Id {get;set;}
public string Title {get;set;}
/* ... more properties here ...*/
}
public class Release {
public int Id {get;set;}
public int FilmId {get;set;}
public virtual Film Film {get;set;}
public virtual ICollection<ReleaseDate> ReleaseDates { get; set; }
/* ... more properties here ...*/
}
public class ReleaseDate {
public int Id {get;set;}
public DateTime Date {get;set;}
public int ReleaseId {get;set;}
public virtual Release Release {get;set;}
/* ... more properties here ...*/
}
Now, I want to order the Films by the earliest release date, but obviously a film could have no releases, and a release could have no release dates (again, 1-* relationships). The SQL equivalent would be...
SELECT * /* or whatever columns...*/
FROM dbo.Films F
LEFT OUTER JOIN dbo.Releases R ON R.FilmId = F.Id
LEFT OUTER JOIN dbo.ReleaseDates RD ON RD.ReleaseId = R.Id
ORDER BY RD.[Date] ASC /* or DESC */
How can I go about doing this?
var orderedFilms = Films.OrderBy(a=> a.Releases.Any() ?
a.Releases.Select(x=>x.ReleaseDates.Any() ?
x.ReleaseDates.Min(d=>d.Date).Date :
DateTime.Now).Min() : DateTime.Now);
Well, I changed my approach to this problem and resolved it based on the "normal" approaches out there, one of which was given as answer but subsequently deleted by the poster. What I ended up doing is moving my select down to the repository layer where I do have the DbContext and was able to do a "simple" left outer join style query like this...
var films = (from f in db.Films
join r in db.Releases on f.Id equals r.FilmId into FR
from a in FR.DefaultIfEmpty()
join d in db.ReleaseDates on a.Id equals d.ReleaseId into RRD
from b in RRD.DefaultIfEmpty()
orderby b.Date ascending
select f);
#KingKing, thanks for your answer, I think it may come in handy in some other places where we have these sort of aggregate fields based on properties of sub-collections or even properties of sub-sub-collections.
join diffrent field type in linq
public partial class Product
{
public int ID { get; set; }
public string CategoryID
{
get { return Myclass.increse(CategoryID); }
set { CategoryID = value; }
}
public string Name { get; set; }
}
public partial class ProductCategory
{
public int ID { get; set; }
public string Name { get; set; }
}
var query = (from c in dContext.ProductCategories
join p in dContext.Products
on Myclass.EncodeMD5(c.ID.ToString()) equals p.CategoryID
select new { id = p.ID, cat = p.CategoryID, name = p.Name, cat1 = c.Name }
).ToList();
The field should be converted to string
Then function runs EncodeMD5
error:
LINQ to Entities does not recognize the method 'System.String
EncodeMD5(System.String)' method, and this method cannot be translated
into a store expression.
You cannot call arbitrary .NET methods in LINQ-to-(some database backend) - the entire point of EF (etc) is that it wants to create SQL from your expression - something involving a where clause. It can work with simple properties and operators, and a few methods it knows about and can map into SQL, but it can't perform something it has never heard of (increse, EncodeMD5, etc) how would it know what SQL to write?
With something like MD5, your best bet would be to store the MD5 hash in the underlying table along with the ID. Likewise with the CategoryID's "increse" (whatever that is). So your query would end up working off these pre-calculated values:
on c.IDHash equals p.CategoryIDHash