I have those models
class Artist
{
public int Id { get; set; }
[StringLength(500)]
public string Name { get; set; }
[StringLength(50)]
public string LastName { get; set; }
public virtual ICollection<SimilarArtist> SimilarArtists { get; set; }
}
class SimilarArtist
{
public int Id { get; set; }
public int ArtistId { get; set; }
[ForeignKey("ArtistId")]
public Artist Artist { get; set; }
public int Similar_Artist_Id { get; set; }
}
So each artist have links to other 5 from the same table. When the migration generate database it made that stracture.
SELECT [Id]
,[Name]
,[LastName]
FROM [dbo].[Artists]
SELECT [Id]
,[ArtistId]
,[Similar_Artist_Id]
FROM [dbo].[SimilarArtists]
So when I do select the model it return this
var similar = _db.Artists.FirstOrDefault(x => x.Name == id).SimilarArtists.FirstOrDefault();
//similar.ArtistId
//similar.Id
//similar.Similar_Artist_Id
//similar.Artist //the object which return main artist
The question is how I can get in "var similar" not just Similar_Artist_Id but also name and lastname in the same request (without making requests by Similar_Artist_Id)
var similarId = model.SimilarArtists.FirstOrDefault().Id;
var artiest = _db.Artists.Where(x.Id = similarId);
or just:
similar.Artist.Name
Or if you want to be able to have strongly-type property such as similar.ArtistName, create a [NotMapped] getter property.
class SimilarArtist
{
public int Id { get; set; }
public int ArtistId { get; set; }
[ForeignKey("ArtistId")]
public Artist Artist { get; set; }
public int Similar_Artist_Id { get; set; }
[NotMapped]
public string ArtistName
{
get
{
return this.Artist.Name;
}
}
}
You can do
var similar = _db.Artists.Where(x => x.Name == id)
.Select(a => a.SimilarArtists.FirstOrDefault())
.FirstOrDefault();
This gives you the first SimilarArtists (with all of its properties) of the first Artists matching the predicate x.Name == id.
Related
I want to reduce duplicated code. In order to achieve that I want to reference the projections of my Entities.
Entities
public class Category
{
public string Id { get; set; }
public string CategoryName { get; set; }
public static Expression<Func<Category, Category>> Proj() => c => new Category
{
CategoryName = c.CategoryName
};
}
public class Image
{
public string Id { get; set; }
public string Url { get; set; }
public static Expression<Func<Image, Image>> Proj() => i => new Image
{
Url = i.Url
};
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public ICollection<Image> Images { get; set; }
public Category Category { get; set; }
}
Projection Query
var categoryProjection = Category.Proj().Compile();
var products = _ctx.Products.Select(p => new Product
{
Id = p.Id,
Name = p.Name,
Images = p.Images.AsQueryable().Select(Image.Proj()).ToHashSet(),
Category = categoryProjection.Invoke(p.Category)
});
When I execute the projection then it will work correctly for Product and Images. But for Category the genereted SQL will contain all Columns (Id and CategoryName).
Hello I want to sort my end result using related entity property which is in this case Locality. I got the keyword from client end as a string that includes column name and sort direction eg. "locality=asc" but when I do orderby with any parent entity properties it run fine however, the property with related entity gives me an error by saying that customer object does not have any locality property
here is my both class customer and Address
public class Customer : IEntity
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public Guid UserId { get; set; }
public DateTime DateCreated { get; set; }
public DateTime LastUpdated { get; set; }
[ForeignKey("Address")]
public Guid AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address: IEntity
{
public Guid Id { get; set; }
public string Lat { get; set; }
public string Lon { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Locality { get; set; }
}
Here I am trying to sort it with Address property like locality
int skip = (pageNum - 1) * pageSize;
if (skip < 0)
{
skip = 0;
}
searchTerm = searchTerm.ToLower();
var query = _context.Customers.Include(q => q.Address)
.Where(c => c.FirstName.ToLower().Contains(searchTerm)
|| c.LastName.ToLower().Contains(searchTerm)
|| c.Email.ToLower().Contains(searchTerm)
|| c.Mobile.ToLower().Contains(searchTerm));
//var sortOrderSplit = sortOrder.Split('=');
if (sortOrderSplit[0].ToLower() != "locality")
{
query = query.OrderByField("Email", "asc");
}
{
query = query.OrderByField("locality", "asc"); //that gives me an error because type is Address not Customer
}
var customers = query
.Skip(skip)
.Take(pageSize)
.ToList();
u want order by Locality ASC,right?
I think Class type of query is IEnumerable,so you can use lumbda expression.
because Locality is in Address Class,should follow the flow Customer => Address => Locality,not only search property Locality.
if (sortOrderSplit[0].ToLower() != "locality")
{
query = query.OrderBy(o => o.Email);
}
else
{
query = query.OrderBy(o => o.Address.Locality);
}
If your two entity classes have One-to-One relationship, you must add
public Customer Customer { get; set; }
into your Address class too.
Do this and try again.
This a simple project where users can search for job postings by area of expertise. The relationship between Areas and Postings are Many-to-many. I seem to be able to get to the very last part of retrieving the correctly filtered list, but getting back into the view model keeps giving me different errors:
ViewModel:
public class AreaOfertasViewModel
{
public Oferta UnaOferta { get; set; }
public SelectList AreasTrabajo { get; set; }
public IEnumerable<Oferta> Ofertas { get; set; }
public int idArea { get; set; }
public AreaOfertasViewModel()
{
this.UnaOferta = UnaOferta;
this.Ofertas = new List<Oferta>();
cargarAreas();
}
private void cargarAreas()
{
PostulaOfertaContext db = new PostulaOfertaContext();
this.AreasTrabajo = new SelectList(db.Areas, "areaId", "Area");
}
}
}
Controller:
public ActionResult SearchXArea()
{
return View(new AreaOfertasViewModel());
}
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id);
var ofertas = from c in db.Ofertas.Where(r => r.AreaTrabajo == area)
select c;
aovm.Ofertas = (IEnumerable<Oferta>)ofertas.ToList();
return View(aovm);
}
The line giving me issues is
aovm.Ofertas = (IEnumerable)ofertas.ToList();
I've tried List<> for Ofertas, and I've tried leaving it as .ToList() without casting, and casting it as different things, but it gives me errors about not being able to cast it, and "Cannot compare elements of type 'System.Collections.Generic.List`1'. Only primitive types, enumeration types and entity types are supported."
What's the solution here?
Model for AreaTrabajo:
public class AreaTrabajo
{
[Key]
public int areaId { get; set; }
public string Area { get; set; }
public virtual List<Oferta> oferta { get; set; }
}
Model for Oferta:
public class Oferta
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Titulo { get; set; }
[Required]
public DateTime Vencimiento { get; set; }
[Required]
public string Cargo { get; set; }
[Required]
public int HorarioComienzo { get; set; }
[Required]
public int HorarioFin { get; set; }
[Required]
public string DescripcionTareas { get; set; }
public int Remuneracion { get; set; }
[Required]
public int RangoEdadMin { get; set; }
[Required]
public int RangoEdadMax { get; set; }
public string TipoFormacion { get; set; }
public string Idiomas { get; set; }
public string Competencias { get; set; }
public string OtrosEstudios { get; set; }
public string Estado { get; set; }
public virtual List<AreaTrabajo> AreaTrabajo { get; set; }
public virtual TipoContrato TipoContrato { get; set; }
public virtual Empresa Empresa { get; set; }
public virtual List<Postulante> Postulantes { get; set; }
}
Answer
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I needed to filter out from the many-to-many relationship, and this solved it.
You are getting an error because the actual sql is executed when you call tolist(). The error is in your sql because you are comparing AreaTrabago to a list.
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I couldn't get the many-to-many relationship, and this solved the filtering problem perfectly.
So I have these classes:
[Table("OrderInfo")]
public class OrderInfo
{
public long ID {get; set;}
public long OrderID {get; set;}
public virtual Order Order { get; set; }
public long ItemID {get; set;}
public double Qty { get; set; }
public virtual Item Item { get; set; }
}
[Table("Items")]
public class Item
{
public Item()
{
this.Orders = new List<OrderInfo>();
}
#region Strings
public string Color { get; set; }
public string FullName { get; set; }
[Column(#"Sheet/Roll")]
public string Type { get; set; }
public string PrimaryMachine { get; set; }
public string Alias { get; set; }
public string Brand { get; set; }
#endregion
#region Long
public long ID { get; set; }
public long? Weight { get; set; }
#endregion
#region Doubles
public double? Size1 { get; set; }
public double? Size2 { get; set; }
public double? Size3 { get; set; }
#endregion.
public virtual ICollection<OrderInfo> Orders { get; set; }
}
and when I use the following code it throws NullReferenceException at me and when in debug the null is the Item portion of OrderInfo I can't figure out how to fix this though!
below is the code calling the data:
int ID = Convert.ToInt32(dgv["ID", dgv.SelectedRows[0].Index].Value);
List<OrderInfo> OrderInfo = new List<OrderInfo>();
OrderInfo = c.OrderInfo.Where(x => x.OrderID == ID).ToList();
if(OrderInfo.Count <= 0)
{
MessageBox.Show("No Info Found For This Order!");
ClearForm();
return;
}
lblPO.Text = "P.O. # " + OrderInfo[0].ID.ToString();
lblRequestedBy.Text = "Requested By: " + OrderInfo[0].Order.RequestedBy;
lblOrderDate.Text = "Ordered On: " + OrderInfo[0].Order.Date.ToShortDateString();
dgvOrderItems.DataSource = OrderInfo.Select(x => new { x.ItemID, x.Qty, x.Item.FullName, x.Item.Brand, x.Item.Color }).ToList();
Entity Framework works lazy by default. You might want to Include your Item when you load your orders. Something like this:
// by using 'Include' you tell EF to fetch Item with your OrderInfo
OrderInfo = c.OrderInfo.Include("Item").Where [...]
I was able to fix this by changing the Query to also have an Include with the items table using my Navigation Property:
so I changed this line
OrderInfo = c.OrderInfo.Where(x => x.OrderID == ID).ToList();
To
OrderInfo = c.OrderInfo.Include("Item").Where(x => x.OrderID == ID).ToList();
and then it all worked fine.
I am using Entity Framework 5 and I have these classes. What I want to do is to be able to get the data to populate the view listed below:
public partial class Subject
{
public int SubjectId { get; set; }
public string Name { get; set; }
public virtual ICollection<Topic> Topics { get; set; }
}
public partial class Topic
{
public int TopicId { get; set; }
public string Name { get; set; }
public int SubjectId { get; set; }
public virtual Subject Subject { get; set; }
public virtual ICollection<SubTopic> SubTopics { get; set; }
}
public partial class SubTopic
{
public int SubTopicId { get; set; }
public string Name { get; set; }
public int TopicId { get; set; }
public virtual Topic Topic { get; set; }
}
Now I am trying to write a LINQ query to populate this class:
public class TopicSubTopicSelect
{
public int TopicId { get; set; }
public int SubTopicId { get; set; }
public string TopicName { get; set; }
public string SubTopicName { get; set; }
}
So far I have this:
return _subjectsRepository
.GetAll()
.Where(s => s.SubjectId == subjectId)
.Include(s => s.Topics.SelectMany(t => t.SubTopics))
.AsEnumerable()
.Select(item => new TopicSubTopicSelect(item.TopicId <<<
item.SubTopicId <<
item.Topic.Name <<
item.Name <<))
.ToList();
Can someone tell me how I can get data from the fields I marked with <<. I tried to do .item.Topic.TopicId etc but that does not seem to work.
You shouldn't start from Subject. You just start from SubTopic Repository, and you won't even need to use .Include. Do it like this:
_subTopicRepository
.GetAll()
.Where(s => s.Topic.SubjectId == subjectId)
.Select(s => new TopicSubTopicSelect()
{
TopicId = s.TopidId,
SubTopicId = s.SubTopicId,
TopicName = s.Topic.Name,
SubTopicName = s.Name
})
.ToList();
As I mentioned in my comment on ataravati's answer, you shouldn't actually have a SubTopicRepository so you are correct in starting at SubjectsRepository however you are querying by the Subject ID so you shouldn't be going via GetAll(), you should have a Get(int id) method. The include should be handled as an implementation detail inside Get as the children (SubTopics) are part of the Subject. That makes the method call look like this instead:
return _subjectsRepository
.Get(subjectId)
.SelectMany(subject => subject.SubTopics))
.Select(subTopic => new TopicSubTopicSelect
{
TopicId = subTopic.TopicId,
SubTopicId = subTopic.SubTopicId,
TopicName = subTopic.Topic.Name,
SubTopicName = subTopic.Name
}).ToList();