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.
Related
Note: These classes are related, but not part of the same Aggregate (like PurchaseOrder and OrderLine) - so I do not have a navigation property from "One" to "Many".
=== Entities ===
public class One
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class Many
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid One { get; set; }
}
=== Contracts ===
public class OneWithMany
{
public Guid Id { get; set; }
public string Name { get; set; }
public IEnumerable<Many>? ManyRelatedObjects { get; set; }
}
I want to select all One objects and any related Many objects from DbSet/DbSet into OneWithMany.
To ensure I don't miss properties added in future I am using ProjectTo in AutoMapper - but I can't work out how to fit it into the equation.
Unfortunately, it seems Entity Framework does not support GroupJoin.
The solution is to do the projection and as much filtering as possible as two separate queries, and then combine them into a result in memory.
If you find EF related answers on the web related to GroupJoin make sure you check the example code to see if they are actually showing code working on arrays instead of DbSet.
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 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 am an absolute novice at using ASP.NET MVC3, and I'm having a great deal of trouble figuring out how to do something that is probably very easy.
Here's my public class:
public class Proposal
{
ProposalDBEntities proposalDB =
new ProposalDBEntities();
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime Target_Finish_Date { get; set; }
public decimal Estimated_Cost { get; set; }
public int Staffing { get; set; }
public decimal Maintenance { get; set; }
public DateTime Date_Added { get; set; }
public int Rating { get; set; }
public decimal VoteAverage { get; set; }
}
I simply want an individual logged-in user to be able to set the value for public int Rating. That is, if the user sets it to 37, he'll see the value 37 when he logs in. But another user who sets it to 50 will see 50. In other words, the value for Rating will be different depending on who's logged in. This seems like it wouldn't be hard at all, but I have no idea where to begin. Any help would be greatly appreciated.
To display the rating: In your view, you would have something like #Html.DisplayFor(p => p.Rating). This is RAZOR syntax. If you are using ASPX, it would be <%: #Html.DisplayFor(p => p.Rating) %>
To have users able to edit the rating (in Entity Framework): How will your user input the rating? Personally, as a beginner, you can create an Entity Data Model and generate code based on your database structure. Then, you can create a controller with CRUD (create, read, update, delete) principles that gives the user the ability to edit his/her rating (Keep in mind that there are views created in addition to edit: create, delete, details, and index. Use what is relevant to you.)
Lots of info to digest, I'm sure. Feel free to ask me anything. I'm in your shoes as well. Hope this helps.
I'm trying to expand beyond the "one-to-one" mapping of models to controllers to views that most mvc(3) tutorials offer.
I have models for a person (operator) and the person's picture. In the database they would correspond to Operator and OperatorPicture tables.
public class Operator
{
public Operator()
{
this.OperatorPictures = new HashSet<OperatorPicture>();
}
[DisplayName("Operator ID")]
public int OperatorID { get; set; }
[Required]
[DisplayName("First name")]
[StringLength(20, ErrorMessage = "The first name must be 20 characters or less.")]
public string OperatorFirstName { get; set; }
[Required]
[DisplayName("Last name")]
[StringLength(20, ErrorMessage = "The last name must be 20 characters or less.")]
public string OperatorLastName { get; set; }
public virtual ICollection<OperatorPicture> OperatorPictures { get; set; } // Nav
}
public class OperatorPicture
{
[DisplayName("Operator Picture ID")]
public int OperatorPictureID { get; set; }
[DisplayName("Operator ID")]
public int OperatorID { get; set; }
[DisplayName("Picture")]
public byte[] Picture { get; set; } // 100x100
[DisplayName("Thumbnail")]
public byte[] Thumbnail { get; set; } // 25x25
public virtual Operator theoperator { get; set; } // FK
}
In most views I would present them together. A list of operators would include a thumbnail picture if it exists. Another screen might show the person's detailed information along witht the full-sized picture.
Is this where viewmodels come into play? What is an appropriate way to use them?
Thanks,
Loyd
Definitely a time for using them. ViewModels are just a way of packaging up all the different bits that go into a view or partialview.
Rather than have just the repository pattern, I have repositories and services. The service has a Get property called ViewModel, that can be called from the controller. EG:
// initialise the service, then...
return View(service.ViewModel)
You can see a more detailed description of my approach in the accepted answer for the following SO question:
MVC Patterns
Note that I am using dependency injection in that code.
It may not be a totally orthodox or canonical approach, but it results in very clean controller code and a easy to use pattern.