I have following objects:
public class City
{
public int CityId { get; set; }
public string Name { get; set; }
public virtual ICollection<CityTranslation> CityTranslations { get; set; }
}
public class CityTranslation
{
public int CityId { get; set; }
public string LanguageCode { get; set; }
public string Translation { get; set; }
public virtual City City { get; set; }
}
City table contain default language value in Name field other translations are in CityTranslation table.
I am having problem to get value by language from this.
I am trying to execute following:
public virtual IEnumerable<City> GetAllByLanguage(string language)
{
if (language != "en")
{
var data = from c in context.Cities
join t in context.CityTranslations
on c.CityId equals t.CityId
&& t.LanguageCode == language
select c;
}
else
{
return dbSet.ToList();
}
}
But I am gettings compile error.
Operator '&&' cannot be applied to operands of type 'int' and 'bool'
plus some casting errors.
What should I do to get value from translation table?
Others have spotted the issue, but you shouldn't even need the join - EF will handle it:
var data = from t in context.CityTranslations
where t.LanguageCode == language
select t.City;
The second predicate should not be part of the join:
var data = from c in context.Cities
join t in context.CityTranslations
on c.CityId equals t.CityId
where t.LanguageCode == language
For a join on multiple values you need to create composite key using anonymous types so your join statement needs to be something like
on new {t.CityId, t.languageCode} equals new {c.CityId, language}
Related
looks like I got stuck with a nested Linq Query. I have 4 Tables which I want to join. Basically a journal has one Recipient and multiple Readers. I'd like to show the Journal with it's Recipient and all it's Readers. Here's the EF Query
var myJournals = (
from s in db.Journals
where !s.Blacklist
join recToJournals in db.RecipientsToJournals on s.JournalID equals recToJournals.JournalID
join recipients in db.Recipients on recToJournals.RecipientID equals recipients.RecipientID
join reaToJournals in db.ReadersToJournals on s.JournalID equals reaToJournals.JournalID
join readers in db.Readers on reaToJournals.ReaderID equals readers.ReaderID
select new AnalysisViewModel
{
JournalID = s.JournalID,
Title = s.Title,
RecipientName = recipients.FullName,
ReaderList = readers.FullName.ToList()
});
return View(myJournals);
Here's the ViewModel:
public class AnalysisViewModel
{
public int JournalID { get; set; }
public string Title { get; set; }
public List<Char> ReaderList { get; set; }
public string ReaderName { get; set; }
public string RecipientName { get; set; }
}
Here I'll get an Exception System.NotSupportedException: The method 'ToList' is not supported when called on an instance of type 'String'.
If I use ReaderName = readers.FullName it works, but I get a List with multiple Journals and their Readers.
How can I show only one Journal with it's Recipient and all it's Readers?
This does not make sense. Why are you calling ToList on a string? Why would you even want List<char>? Change your model so the type is of string and remove ToString
Change 1 - in your linq statement
ReaderList = readers.FullName // remove .ToList
Change 2 - in your model
public string ReaderList { get; set; }
Although it is not technically wrong it is not best practice to name a property of type string (or any non collection type for that mater) with the suffix List. A more suitable name would be ReaderName.
First of all change your ViewModel
public class AnalysisViewModel
{
public int JournalID { get; set; }
public string Title { get; set; }
public string RecipientFullName { get; set; }
public List<string> ReadersFullNames { get; set; }
}
You need GroupBy
var myJournals = from s in db.Journals
where !s.Blacklist
join recToJournals in db.RecipientsToJournals
on s.JournalID equals recToJournals.JournalID
join recipients in db.Recipients
on recToJournals.RecipientID equals recipients.RecipientID
join reaToJournals in db.ReadersToJournals
on s.JournalID equals reaToJournals.JournalID
join readers in db.Readers
on reaToJournals.ReaderID equals readers.ReaderID
select new
{
JournalID = s.JournalID,
Title = s.Title,
RecipientFullName = recipients.FullName,
ReaderFullName = readers.FullName
};
var result = myJournals.GroupBy(j => new { j.JournalID, j.Title, j.RecipientFullName })
.Select(g => new AnalysisViewModel
{
JournalID = g.Key.JournalID,
Title = g.Key.Title,
RecipientFullName = g.Key.RecipientFullName,
ReadersFullNames = g.Select(r => r.ReaderFullName).ToList(),
}
)
.ToList();
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 multiple join query like this:
public static List<Answer> GetDetailedAnswers(string Tag)
{
using (Database db = new Database())
{
List<Answer> answer =
from quest in db.Question
join answ in db.Answer on quest.ID equals answ.QuestionID
join deal in db.Dealer on answ.DealerID equals deal.ID
join country in db.Country on deal.CountryID equals country.CountryID
where quest.ParentSection == Tag
select new
{
ParentSection = quest.ParentSection,
Section = quest.Section,
Dealer = deal.Name,
OriginalAnswer = answ.Original,
EngAnswer = answ.English,
Region = country.Country
}.ToList();
return answer;
}
}
And i have an internal class like this:
public class Answer
{
public string ParentSection { get; set; }
public string Section { get; set; }
public string Dealer { get; set; }
public string OriginalAnswer { get; set; }
public string EngAnswer { get; set; }
public string Region { get; set; }
}
I get an error on the last join. It says "the type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'"
What did i miss? Thx
For the error: "AnonymousType#1 does not contain a definition for 'ToList' and no extension method 'ToList'", You can do following.
public static List<Answer> GetDetailedAnswers(string Tag)
{
using (Database db = new Database())
{
List<Answer> answer =
(from quest in db.Question
join answ in db.Answer on quest.ID equals answ.QuestionID
join deal in db.Dealer on answ.DealerID equals deal.ID
join country in db.Country on deal.CountryID equals country.CountryID
where quest.ParentSection == Tag
select new Answer
{
ParentSection = quest.ParentSection,
Section = quest.Section,
Dealer = deal.Name,
OriginalAnswer = answ.Original,
EngAnswer = answ.English,
Region = country.Country
}).ToList();
return answer;
}
}
You need to surround you query within round brackets and then apply .ToList() method to it.
Please check the data type of
deal.CountryID and country.CountryID. this should be same
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
LINQ to SQL: Return anonymous type?
What return type do I use for a List<> on a linq join? I'm joining multiple tables below, I'm getting the error 'Cannot implicitly convert type System.Collections.Generic.List<AnonymousType#1> to System.Collections.Generic.List<CargoTanksDAL.aspnet_Users>
public List<> GetAspnetUsersWithMembershipAndCompany()
{
using (DevCargoEntities db = new DevCargoEntities())
{
var users = from u in db.aspnet_Users
join mem in db.aspnet_Membership on u.UserId equals mem.UserId
join cl in db.CT_CompanyLogIn on u.UserName equals cl.UserLogIn
join companies in db.CT_Companies on cl.CompanyID equals companies.CompanyID
select new
{
u.UserId,
u.UserName,
mem.Email,
mem.IsLockedOut,
mem.IsApproved,
mem.CreateDate,
companies.CompanyName
};
return users.ToList();
}
}
None. The join does not matter here, the select does, and you select an anonymous type. You can't return an anonymous type. Better create a new class that contains the properties you want to return and instanciate that type.
You could theoretically return dynamic or object, but that is a path you really really don't want to walk. Trust me on that.
I would have made a new class.. for this user..
public class SomeKindOfUser
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public bool IsLockedOut { get; set; }
public bool IsApproved { get; set; }
public DateTime CreateDate { get; set; }
public string CompanyName { get; set; }
}
Now you can use
public List<SomeKindOfUser> GetAspnetUsersWithMembershipAndCompany()
Then in the select :
select new SomeKindOfUser
{
UserId = u.UserId,
UserName = u.UserName,
Email = mem.Email,
IsLockedOut = mem.IsLockedOut,
IsApproved = mem.IsApproved,
CreateDate = mem.CreateDate,
CompanyName = companies.CompanyName
};
Get all the NWatchRelation records from the DBContext that overlap those in the relationsCollection.
The same Id, RelatedNodeId, and RelationType (enum: int) should be what's considered a match.
public class NWatchRelation : INWatchRelation
{
public int Id { get; set; }
public int NodeId { get; set; }
public NWatchNode Node { get; set; }
public int RelatedNodeId { get; set; }
public NWatchNode RelatedNode { get; set; }
public NWatch.NWatchRelationType RelationType { get; set; }
}
INWatchRelation[] relationsCollection = GetRelations();
You can do a LINQ join between these 2 collections.
var result = from a in db.NWatchRelations.AsEnumerable()
join b in relationsCollection on a.RelatedNodeId equals b.RelatedNodeId
&& a.Id equals b.Id
&& a.RelationType equals b.RelationType
select a;
The only way you can do that fully in LINQ to Entities is to manually compose UNION ALL query by using Queryable.Concat like this:
IQueryable<NWatchRelation> query = null;
foreach (var relation in relationsCollection)
{
var m = relation;
var subQuery = db.NWatchRelations
.Where(r => r.Id == m.Id
&& r.RelatedNodeId == m.RelatedNodeId
&& r.RelationType == m.RelationType);
query = query == null ? subQuery : query.Concat(subQuery);
}
But please note that it's a limited approach and will not work if the relationsCollection is big.
You could create a kind of unique key using the three values:
//To create a unique key (an string, which is a primitive type) combining the three values
var keys=relationsCollection.Select(e=>e.Id+"-"+e.RelatedNodeId+"-"+ ((int)e.RelationType)).Distinct();
var query=db.NWatchRelations.Where(r=>keys.Any(k=>k == (SqlFunctions.StringConvert((double)r.Id)+"-"+
SqlFunctions.StringConvert((double)r.RelatedNodeId )+"-"+
SqlFunctions.StringConvert((double)((int)r.RelationType)) ));
If your NWatchRelations table doesn't have many rows or relationsCollection is a small collection, please, use one of the alternatives that were proposed earlier at your convinience.
Also you can have the directly linked like this
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public NWatchRelation()
{
this.INWatchRelation = new HashSet<INWatchRelation>();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<INWatchRelation> INWatchRelation { get; set; }
But the entiry relation must be liked like this in order to work properly
Then you could select/list it like this
db.NWatchRelation.INWatchRelation.ToList();