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
Related
How can i select data from two tables using SQL query using ef core.
Below are two tables
public class Category
{
public int Id { get; set; } // Don't want to return this.
public string Name { get; set; } // Only want to return this.
}
public class Product
{
public int ProductId {get;set;}
public string Name { get; set; }
public int CategoryId {get;set;}
}
I want to execute Select P.Name , C.Name from tblCategory C JOIN tblProduct P ON C.Id = P.CategoryId
in entity framework core.
One option is to use table valued functions but i dont want to consider it?
I dont want to use linq because the sql generated is not efficient.
Above is just an example not a real scenario.
If you want to do this using EF Core instead of ADO.NET or Dapper, you can use raw Sql Queries as below:
EF Core 2.1 example:
var blogs = context.Blogs
.FromSql("SELECT * FROM dbo.Blogs")
.ToList();
In EF Core 3.1, FromSql is Obsolete, Hence use FromSqlRaw
var blogs = context.Blogs
.FromSqlRaw("SELECT * FROM dbo.Blogs")
.ToList();
Similarly, your query can be executed as
var results = context.ProductCategories.FromSqlRaw(Select P.Name as ProductName, C.Name as CategoryName from tblCategory C JOIN tblProduct P ON C.Id = P.CategoryId)
Note: Also, you need to define ProductCategories in context class.
public DbQuery<ProductCategory> ProductCategories { get; set; }
ProductCategory.cs
public class ProductCategory
{
public string ProductName { get; set; }
public string CategoryName { get; set; }
}
Here, ProductCategory is known as query type in EF Core 2.1.
In EF Core 3.0 the concept was renamed to keyless entity types. It serves as return type for raw Sql Queries.
You can refer learn.microsoft.com for more details
You can just execute an SQL statement with the query that you want:
using (var connection = new SqlConnection(_ConnectionString))
{
connection.Open();
{
string query = #"select P.Name, C.Name from tblCategory C JOIN P ON C.Id=P.CategoryId";
result = (await connection.QueryAsync<MyDto>(query)).ToList();
}
}
In EF you would normally not use a raw SQL query for something so simple.
Instead, add a Navigation Property to from Product to Category:
public class Category
{
public int Id { get; set; } // Don't want to return this.
public string Name { get; set; } // Only want to return this.
}
public class Product
{
public int ProductId {get;set;}
public string Name { get; set; }
public Category Category {get;set;}
public int CategoryId {get;set;}
}
Then you can write a LINQ query like
from p in db.Product
select new {ProductName = p.Name, CategoryName = p.Category.Name };
In Code-First, this will also ensure that you can't have a Product whose CategoryId is not the Id of some Category by creating a Foreign Key in the database, and (at least for SQL Server) create a non-clustered index on Product.CategoryId for improved performance.
I have two tables LookUpCodes and LookUpValues they are defined as below:
public partial class LookUpCodes
{
public int Id { get; set; }
public int? CodeId { get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
public partial class LookUpValues
{
public int Id { get; set; }
public int CodeId { get; set; }
public string CodeValue { get; set; }
public bool? IsActive { get; set; }
}
Each LookUpCode can have multiple Values associated with it. I want to pass in a code and get associated list of values back.
This is probably a common question as I have seen this everywhere, I am not looking for an answer per se, if someone can just explain how to build the proper query I would be obliged.
Here is what I have done so far:
public IEnumerable<LookUpValues> GetValuesByCode(string cd)
{
var query = from code in _context.LookUpCodes
join values in _context.LookUpValues on code.CodeId equals values.CodeId
where code.Code == cd
select new { LookUpValues = values };
return (IEnumerable<LookUpValues>) query.ToList();
}
You are very close to that you are looking for:
public IEnumerable<LookUpValues> GetValuesByCode(string cd)
{
var query = from code in _context.LookUpCodes
join values in _context.LookUpValues
on code.CodeId equals values.CodeId
where code.Code == cd
select values;
return query;
}
Since you have written the join, I assume that you have understood how it works. However let's revisit it:
from a in listA
join b in listB
on a.commonId equals b.commonId
In the above snippet we join the contents of listA with the contents of listB and we base their join on a commonId property existing in items of both lists. Apparently the pair of a and b that fulfill the join criterion it would form one of the possible many results.
Then the where clause is applied on the results of the join. The joined items that pass thewherefilter is the new result. Even at this point the results is still pairs ofaandb`.
Last you project, using the select keyword each pair of the results to a new object. In your case, for each pair of code and values that passed also the where filter, you return only the values.
Here is my linq to sql query which is working fine but when i cast and return the data I get casting error.
var productImages = from prod in context.seller_productinventory.AsEnumerable()
join prodImage in context.seller_productimages on prod.prdid equals prodImage.prdid
join category in context.mstr_scategory on prod.mcid equals category.CategoryID
join subcategory in context.mstr_scategory on prod.scid equals subcategory.CategoryID
select new
{
ProductId = prod.prdid,
Category = category.CategoryName,
Subcategory = subcategory.CategoryName,
Image1 = prodImage.image1Path,
Image2 = prodImage.image2Path,
Image3 = prodImage.image3Path,
Image4 = prodImage.image4Path,
ProductStatusCd = (Convert.ToInt32(prod.isAdminApproved) != 1) ? "Pending Approval" : "Approved"
};
I get error in below code.
return (IEnumerable<ProductImageModel>) productImages.ToList();
My Model Class:
public class ProductImageModel
{
public int ProductId { get; set; }
public string Category { get; set; }
public string Subcategory { get; set; }
public string Image1 { get; set; }
public string Image2 { get; set; }
public string Image3 { get; set; }
public string Image4 { get; set; }
public string ProductStatusCd { get; set; }
}
You are selecting an anonymous object using select new and later you are trying to cast a collection of anonymous objects to IEnumerable<ProductImageModel>, that will fail.
You have two options to fix that.
If your class ProductImageModel is not generated through entity framework then you can use that in your select statement like:
select new ProductImageModel
{
//.... fields
}
Or the other option is to create a temporary template class, and project your fields to that class object.
Remember, If ProductImageModel is framework generated then you can't use that in column projection using select.
From your code, it seems that your class ProductImageModel is actually representing a table from database. You will be needing another class (DTO) with fields specified in select clause.
public class ProductImageModelDTO
{
//your fields
}
and then in your LINQ query:
select new ProductImageModelDTO
{
ProductId = prod.prdid,
//rest of the fields.
Your method return type in that case should be:
IEnumerable<ProductImageModelDTO>
When you do select new { ... }, you're creating anonymous objects. Essentially, you end up with IQueryable<object> and that is contravariant with IEnumerable<ProductImageModel> (i.e., the compiler cannot cast from one to the other). The easiest solution is to select actual ProductImageModels if that's what you're going to use:
select new ProductImageModel
{
...
}
Then, no casting is necessary.
I have a Product table that has no relation defined to the translation table. I added a Translation property to the Product POCO as [NotMapped].
**My Product POCO: **
public partial class Product
{
public int ProductID { get; set; }
public double Price { get; set; }
[NotMapped]
public virtual Translation Translation{ get; set; }
/** Other properties **/
}
I also have a Translation table, and like the name says, it contains all the translations.
Now, the right translation can be retrieved from the database by providing three parameters: LanguageID, TranslationOriginID and ValueID.
LanguageID: ID from the language that the user has defined.
TranslationOriginID: Simply said, 'What table contains the entity that I want the translation for?' In other words, this ID points to another table that contains all possible origins. An origin is a table/entity that can have a translation. E.g: The origin in this example is Product.
ValueID: This is the ID of the entity that I want a translation for.
My Translation POCO:
public partial class Translation
{
public int TranslationID { get; set; }
public byte LanguageID { get; set; }
public short TranslationOriginID { get; set; }
public int ValueID { get; set; }
public string TranslationValue { get; set; }
/** Other properties **/
public virtual TranslationOrigin TranslationOrigin { get; set; }
public virtual Language Language { get; set; }
}
When I want to retrieve all products with their Translation, I execute this code:
List<Product> products = context.Products.ToList();
foreach (Product product in products)
{
product.Translation = context.Translations.FirstOrDefault(y => y.LanguageID == 1 && y.TranslationOriginID == 2 && y.ValueID == product.ProductID);
}
Like you can see, I execute for every product in the list another query to get the translation.
My question:
Is it possible to get all the products and their translation in one query? Or even that I automatically retrieve the right translation when I select a product?
I already tried an .Include() and a .Select(). It didn't work, maybe I did something wrong?
I also tried this method, didn't work either.
Btw, I use Entity framework 5 with .NET 4 (so, Entity Framework 4.4).
Thanks in advance.
Greetings
Loetn
Answer
With the example given by Ed Chapel, I came up with a solution.
return (from p in context.Products
join t in context.Translations
on new
{
Id = p.ProductID,
langId = languageID,
tOriginId = translationOriginID
}
equals new
{
Id = d.ValueID,
langId = d.LanguageID,
tOriginId = d.TranslationOriginID
}
into other
from x in other.DefaultIfEmpty()
select new
{
Product = p,
Translation = x
})
.ToList().ConvertAll(x => new Product()
{
Code = x.Product.Code,
Translation = x.Translation,
/** Other properties **/
});
I don't like proper LINQ in most cases. However, join is one scenario where the LINQ is easy than the extensions methods:
from p in context.Products
join t in context.Translations
on t.ValueID equals p.ValueID
&& t.LanguageID == 1
&& t.TranslationOriginID == 2
into joinT
from x in joinT
select new {
Product = p,
Translation = t,
};
You then loop over the result setting x.Product.Translation = x.Translation.
First of all you should realize that your translations table is not structured like a dba would like it You have a non enforced relationship because depending on the OriginId your valueId references a different table.
Because of this you cannot use lazy loading or includes from EF.
My best idea at this point would to manually join the table on an anonymous type(to include your originId). Afterwards you can iterate over the results to set the translation property
The result would look like this :
var data = from p in context.Products
join pt in context.Translations on new{p.Id,2} equals new {pt.ValueId, pt.OriginId} into trans
select new {p, trans};
var result = data.ToList().Select( a =>
{
a.p.Translations = a.trans;
return a.p;
}).ToList();
With the example that Ed Chapel proposed as a solution, I came up with this.
return (from p in context.Products
join t in context.Translations
on new
{
Id = p.ProductID,
langId = languageID,
tOriginId = translationOriginID
}
equals new
{
Id = d.ValueID,
langId = d.LanguageID,
tOriginId = d.TranslationOriginID
}
into other
from x in other.DefaultIfEmpty()
select new
{
Product = p,
Translation = x
})
.ToList().ConvertAll(x => new Product()
{
Code = x.Product.Code,
Translation = x.Translation,
/** Other properties **/
});
I'm creating a product listing for an online store. It's pretty standard stuff, a page of product thumbnails with brief details, price and a link through to full details.
I'm using a repository pattern, so I have a central data repository which gives me back tables from a SQL server. I've cut a lot of the code out for the sake of brevity, but just so you get the idea:
public class SqlProductsRepository : IProductsRepository
{
private Table<Product> productsTable;
public SqlProductsRepository(string connectionString)
{
var context = new DataContext(connectionString);
productsTable = context.GetTable<Product>();
// More tables set up here
}
public IQueryable<Product> Products
{
get { return productsTable; }
}
// More properties here
}
I have the following objects mapped to tables:
[Table(Name = "Products")]
public class Product
{
[Column(IsPrimaryKey = true)]
public string ProductCode { get; set; }
[Column]
public string Name { get; set; }
[Column]
public decimal Price { get; set; }
public List<ShopImage> Images = new List<ShopImage>();
}
[Table(Name = "Images_Products")]
public class Image_Product
{
[Column]
public int ImageID { get; set; }
[Column]
public string ProductCode { get; set; }
[Column]
public int DisplayOrder { get; set; }
}
[Table(Name = "Images")]
public class Image
{
[Column(Name = "ImageID")]
public int ImageID { get; set; }
[Column]
public bool Caption { get; set; }
}
If I perform the following query:
// 'db' is the repository (member variable of the controller class)
IQueryable<Product> products = from p in db.Products
join ip in db.Image_Product on p.ProductCode equals ip.ProductCode
where ip.DisplayOrder == 0
select p;
I get a nice IQueryable full of Product objects. However, what I want to do is populate each object's Images list property with a single Image object, with its ID set from the joined Image_Product table.
So I end up with a list of Products, each with one Image in its Images property, which has the ID of the image for that product in the database where DisplayOrder is 0.
I tried this projection, which I thought made sense:
IQueryable<Product> products = from p in db.Products
join ip in db.Image_Product on p.ProductCode equals ip.ProductCode
where ip.DisplayOrder == 0
select new Product {
ProductCode = p.ProductCode,
Price = p.Price,
Images = new List<Image> {
new Image { ImageID = ip.ImageID }
}
};
Which compiles, but throws a runtime error: Explicit construction of entity type 'xxx.Product' in query is not allowed.
Yet elsewhere in the project I do this:
var pages = from i in db.TemplatePageNavigationItems
orderby i.DisplayOrder
select new NavigationItem {
ID = i.PageID,
ParentID = i.ParentID,
Text = i.Name,
Title = i.Name,
Url = (i.Folder == null) ? "" : i.Folder
};
And get no complaints! I assume it's something to do with the first query returning an IQueryable<Product> but I'm not sure why.
Two questions really: why is this not allowed in the first situation, and what should I be doing in order to get my desired result?
As the error says, you can't construct explicit entity types (Product is just that) in your query which should return IQueryable<Product>. Your pages query will return IEnumerable<NavigationItem> and NavigationItem does not seem to be an entity type defined in the database.
You could try returning IEnumerable<Product> in your first query or define a separate type and return IEnumerable of that instead, if you need to project explicit, custom tailored instances of an object.