I'm using Entity Framework for my DB access.
One of the entities is Products, and a Product can have many Terms.
Here's the Term class:
public partial class Term
{
public short ID { get; set; }
public short ProductID { get; set; }
public byte TermSegmentID { get; set; }
public byte MinTerm { get; set; }
public byte MaxTerm { get; set; }
public virtual Product Product { get; set; }
}
Having selected a list of all my products, I've been trying to return the minimum value in MinTerm - that's the lowest value for all Products, not each one.
Can anyone help? This is proving difficult for my limited knowledge.
Thanks in advance.
This should do what you want:
byte minTerm = yourProducts.SelectMany(x => x.Terms).Min(x => x.MinTerm);
Does Product have a Terms property? If so, it's pretty easy:
var minMinTerm = products.SelectMany(product => product.Terms)
.Min(term => term.MinTerm);
The SelectMany method "flattens" a sequence - so you end up with a single sequence of terms, logically the concatenation of each of the terms sequences from the products.
Related
We have been implementing our ERD in EF.
Code First for Project
public class Project
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProjectID { get; set; }
[Index("IX_ProjectGUID", IsUnique = true)]
[Required]
public Guid GUID { get; set; }
[MaxLength(256), Index("IX_ProjectName", IsUnique = true)]
[Required]
public string Name { get; set; }
public virtual ICollection<UserAttribute> UserAttributes { get; set; }
}
Code First for UserAttributes
public class UserAttribute
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserAttributeID { get; set; }
[Index("IX_Project_Atttribute_Name", 1, IsUnique = true)]
public int ProjectID { get; set; }
[ForeignKey("ProjectID")]
public virtual Project Project{ get; set; }
[Index("IX_Project_Atttribute_Name", 2, IsUnique = true)]
public int AttributeTypeID { get; set; }
[ForeignKey("AttributeTypeID")]
public virtual SystemUserAttribute SystemUserAttribute { get; set; }
[MaxLength(256), Index("IX_Project_Atttribute_Name", 3, IsUnique = true)]
[Required]
public string Name { get; set; }
public virtual ICollection<UserBooleanAttribute> UserBooleanAttributes { get; set; }
}
So you can see from the last line of each of those classes a 1-many bidirectional relationship is setup.
Before I introduced this 1-many collection I would of been required to todo:
var jar = context.Projects
.Where(p=>p.ProjectID==1)
.Join(
context.UserAttributes,
a => a.ProjectID, b => b.ProjectID,
(a, b) => new {a, b});
Now I only have to do:
Projects.Where(prj=>prj.ProjectID==1).Select(ua=>ua.UserAttributes).Single()
Since Lazy-Loading in effect, is there really no degradation to performance?
*Single -- Why do I need to call this or something similar like FirstOrDefault?
Looks ok. A few quirks to it, like why you are assigning both an ID and GUID to a project. Really should be one or the other.
Single seems out of place because you are selecting the UserAttributes, which could be one or more of them. Single implies there is only one, and if that was true, your design is more complex than it should be.
I assume you'll be adding navigation properties for string and integer as well, which is just fine.
The User*Attributes classes should also have navigation properties to UserAttributes as well.
I've tried analyzing your design, and all I can say is it gives me a headache. I'm going to assume there is some outside reason you've chosen the PK's you have instead of using natural keys. From a glance, UserAttributes seems poorly named. It's not user attributes, it appears to be a project's attributes (or attributes that are assignable to a user for each project). I would also ask if breaking your attributes up into 3 separate tables instead of always serialzing the value into a string is worth the headaches, because it's not likely to save you any space (with the exception of integer -- perhaps) and greatly slow down every query you need to make.
I am using EF6, WebApi2, AngularJS and BreezeJs.
I have the following entities:
Person
{
public string Name { get; set;}
public virtual ICollection<GenericProfileCountry> Countries { get; protected set; }
}
public class GenericProfileCountry
{
public string PersonId{ get; set; }
public virtual Person Person{ get; set; }
public string CountryIso { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public string Iso { get; set; }
public string Name { get; set; }
}
Now I have a query that brings all Persons through breeze as follows:
return zEntityQuery.from('Contacts').expand('Profile, Countries')
.orderBy(contactOrderBy)
.toType(entityName)
.using(self.manager).execute()
.to$q(querySucceeded, self._queryFailed);
What I would like to do is perform a where statement on the above query with criteria that are on the intermediate entity. So say I want to bring only contacts that their first country (a person can have multiple countries) iso code is equal to 'GB'.
In Linq it would be something like Contacts.Where(contact => contact.Countries.First().CountryIso == 'GB')
Could something similar be expressed in the where(predicate) of breeze? I thought of going the other way (start from the intermediate table and filter from there), but not sure if that is the correct approach.
You can achieve that by creating a predicate with the keyword any or all
.where('Countries','any','CountryIso','eq','GB')
In case you want to create a predicate on grand children : BreezeJS Predicates on 2nd level expanded entities
Edit
If you want to get the first contacts whose countries Isos start with 'GB', you can achieve that by:
Jay's suggestion.
using Linq at Breeze controller:
public IQueryable<Person> ContactsWithFilteredCountryIso(string CountryIso)
{
return _contextProvider.Context.Persons.Where(p => p.Countries.First().CountryIso== CountryIso);
}
Then on the client:
return zEntityQuery.from('Contacts')
.withParameters({ CountryIso: "GB"})
.expand('Profile, Countries')
.orderBy(contactOrderBy)
.toType(entityName)
.using(self.manager).execute()
.to$q(querySucceeded, self._queryFailed);
Writing a select projection on countries with bringing up Contacts can be implemented by issuing a Breeze query on countries and expanding contact:
return zEntityQuery.from('Countries').expand('Contact')
.select('Country.name')
.where('CountryIso','eq','GB')
.orderBy(contactOrderBy)
.toType(entityName)
.using(self.manager).execute()
.to$q(querySucceeded, self._queryFailed);
I wonder if I could get some help with the following. I'm retrieving set of data as follows using EF.
var booking = this.GetDbSet<Booking>().Include(c => c.BookingProducts.Select(d => d.Product.PrinterProducts.Select(e => e.ProductPrices))).Single(c => c.BookingId == bookingId)
Within a PrinterProduct there is a foreign key PrinterId for an additional entity Printer. With the Booking Entity I also have PrinterId also linked by foreign key to the additonal entity Printer.
What I'm hoping to do is retrieve only the PrinterProduct relating to the PrinterId held in the booking entity rather that all the PrinterProducts as in my code. I've tried to use Join but have tied myself in knots!
Grateful for any help!
Edit:
Object structure:
public class Booking
{
public Guid BookingId { get; set; }
public string BookingName { get; set; }
public Printer Printer { get; set; }
public IEnumerable<BookingProduct> BookingProducts { get; set; }
}
public class BookingProduct
{
public int BookingProductId { get; set; }
public Booking Booking { get; set; }
public Product Product { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public IEnumerable<PrinterProduct> PrinterProducts { get; set; }
}
public class PrinterProduct
{
public int PrinterProductId { get; set; }
public Product Product { get; set; }
public Printer Printer { get; set; }
public IEnumerable<ProductPrice> ProductPrices { get; set; }
}
public class ProductPrice
{
public int ProductPriceId { get; set; }
public PrinterProduct PrinterProduct { get; set; }
public decimal Price { get; set; }
}
public class Printer
{
public int PrinterId { get; set; }
public string PrinterName { get; set; }
public IEnumerable<Booking> Bookings { get; set; }
public IEnumerable<PrinterProduct> PrinterProducts { get; set; }
}
Given the newly added class structures in your question, I hope I can clear it up now.
From what I see, Bookings and Products have a many-to-many relation (where BookingProduct is used as the connection). The same is true for Product and Printer (where PrinterProduct is used as the connection).
From what I understand, you are trying to get from a singular Booking item to a singular PrinterProduct. I don't see any efficient way to do this without introducing the possibility of inconsistency with your data. You're expecting some Lists to return you one result. If it's only one result, why is it a List in the first place?
You have a single Booking. You take its BookingProducts. Now you have many items.
You take the Product from each individual BookingProduct. If all BookingProducts have the same product, you're in luck and will only have a List<Product> with a single Product in it. However, there is nothing stopping the system from return many different products, so we are to assume that you now hold a List of several Products
From each Product in the list, you now take all of its PrinterProducts. You now hold many PrinterProducts of many Products.
As you see, you end up with a whole list of items, not just the singular entity you're expecting.
Bookings, Products and Printers are all connected to eachother individually, like a triangle. I have seen scenarios where that is correct, but nine times out of ten, this is not what you want; and only leads to possible data inconsistency.
Look at it this way: Is it ever possible for the Product to have a Printer other than the Printer that is already related to the Booking? If not, then why would you have two relations? This only introduces the possibility that Booking.Printer is not the same as PrinterProduct.Printer.
Your relational model is set up to yield many results, but I think you expect a single result in some places. I would suggest taking another look at your data model because it does not reflect the types of operation you wish to perform on it. Change the many-to-many relations to one-to-many where applicable, and you should be able to traverse your data model in a more logical fashion, akin to the answer I provided in my previous answer.
If you've set up navigational properties, you can just browse to it:
var myBooking = ... //A single Booking, don't know how you retrieve it in your case.
var myPrinter = myBooking.Printer; //the Printer that is related to the Booking.
var myPrintproducts = myPrinter.PrintProducts; //The products that are related to the printer.
You don't need to keep nesting select statements, that only creates unnecessary confusion and overhead cost.
Keep in mind that you need to do this while in scope of the db context. Every time you try to access a property, EF will fill in the needed variables from the database. As long as there is an open db connection, it works.
Edit
If you really need to optimize this, you can use a Select statement. But you only need a single one. For example:
var myPrintproducts = db.Bookings.Single( x => x.ID == some_id_variable ).Select( x => x.Printer.PrintProducts);
But unless you have a very strict performance requirement, it seems better for code readability to just browse to it.
I know if I want to create a multilingual MVC4 application I would use resource files according to CultureInfo, but that would be useful for application's labels, messages, titles..etc, however I was thinking about defining a list of counties' names and their cities in many languages, now should I define them in a resource files (which can be exhausting) or should I use a table with many columns for each language?
And if I used resource files, how can I tell which country a user is from when he register in the system?
Which one is best practice? Is there any other approach?
Using multiple columns for each language will work, but it will also get out of hand pretty quickly as more columns and languages need to be added down the road. So I'd advise against that approach.
What you can do however is move the columns that need to be localized to a different table with a compound primary key. Here's a simple example with a cities table :
You'll have classes that look somewhat like this :
// City.cs
public class City
{
public int CityId { get; set; }
public string UnlocalizedField1 { get; set; }
public string UnlocalizedField2 { get; set; }
// Optional
public virtual List<CityTranslation> Translations { get; set; }
}
// CityTranslation.cs
public class CityTranslation
{
public int CityId { get; set; }
public string LanguageId { get; set; }
public string LocalizedField1 { get; set; }
public string LocalizedField2 { get; set; }
}
Then it becomes rather trivial to query your data in the language you need.
I have two different collections like below
public class Student
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Skills
{
public int SkillID { get; set; }
public int StudentID { get; set; }
public string Keyskill_Name { get; set; }
public int LastUsedYear { get; set; }
}
Here one student can contain multiple keyskils
I just want to fill a new collection like below
public class StudentDetails
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public list<string> Keyskill_Name { get; set; }
}
Please help me. Thanks in advance.
The GroupJoin LINQ method is the perfect solution for this case:
List<Student> students = new List<Student>();
List<Skills> skills = new List<Skills>();
List<StudentDetails> studentDetails = students.GroupJoin(skills, student => student.StudentID, skill => skill.StudentID, (student, skillsForStudent) => new StudentDetails
{
FirstName = student.FirstName,
LastName = student.LastName,
StudentID = student.StudentID,
Keyskill_Name = (from skill in skillsForStudent
select skill.Keyskill_Name).ToList()
}).ToList();
How to use the GroupJoin method?
Call the method from the set that gives a 1 to 1 relation with the result (Here for each Student, there is one and only one corresponding StudentDetails.
The first argument of the method is the set you want to "distribute" on the other items (Here the skills are "distributed" over the entire set of students)
The second and third arguments are used to explain how to make the collision between the elements of the first set and the elements of the second set. Lambda expressions are extremely useful in this case.
Lastly, the fourth argument, is used to define the result. It is a function with 2 parameters : an element of the first set (here students) and its corresponding elements in the second set that have been found using the collision.