I'm using Kendo grid with ForeignKey column with sorting. By default this column is sorted by value but we need it to be sorted by text. Could anyone provide please an example of doing it using ASP.NET Wrappers?
I found the trick was to implement IComparable on the foreign key object, which then sorts by the text name instead of the id in the Kendo grid:
public class MyForeignKeyModel : IComparable<MyForeignKeyModel>
{
public int ID { get; set;}
public string Name { get; set;}
public int CompareTo(MyForeignKeyModel compareTo)
{
return String.Compare(Name, compareTo.Name, StringComparison.InvariantCulture);
}
}
All the other solutions mentioned by users and Telerik look much more complicated!
Reponse by Atanas Korchev (Admin, Kendo UI) We can’t support this in all cases because the data source won’t have all data (it usually has just the foreign key which is the value)
You can use Grouping if that helps to some extend.
Related
I have a project work work with hundreds of grids. On one grid in particular, the original designer created a view and added it as a nested model inside our driver model. This is a problem because Kendo seems to not be able to detect the field type of a field nested this way. When it can't, it assumes the field is a string.
In my particular case, I have two fields that contain dates that we want to filter on, but the date filtering is broken because of this.
I was able to find numerous examples of specifying it in the data source, but only for jquery grids (one example: https://docs.telerik.com/kendo-ui/knowledge-base/use-nested-model-properties ). I can't convert this to mvc because the methods aren't lining up.
Any idea on how to do this in mvc? Note: I also tried just changing the UI on the filter to date and that didn't work either. I got a stack trace claiming date needed to be a string.
As far as I understand the model passed to the Grid's field is structured like this:
public class OrderViewModel
{
public int OrderID
{
get;
set;
}
public CityModel ShipCity
{
get;
set;
}
}
public class CityModel
{
public int CityID
{
get;
set;
};
public string CityName
{
get;
set;
};
}
Then you can utilize the ClientTemplate configuration to get the CityName to populate the column:
columns.Bound(p => p.ShipCity).ClientTemplate("#=ShipCity.CityName#");
For more information refer to the Kendo UI Templates article
or
this forum answer that shows how to set a default to a nested field in a Grid's DataSource Model configuration.
Unfortunately, according to Telerik , the fact is that you simply can't do what I was trying to do. The solution is to flatten the model. I pulled the questionable fields into notmapped fields in the master model.
The relevant part of their response:
In MVC the nested properties are properties to another Model. As the Telerik UI Grid needs a flat structure of data, the nested properties could be shown with the help of a ClientTemplate, but they will always be string typed.
In order to achieve the desired behavior, I would recommend making the pointed Date fields - part of the Main Model and using them as flat data out of the box.
Link: https://www.telerik.com/forums/kendo-mvc-wrapper-grid-how-do-i-specify-the-data-type-of-a-nested-model-field
The caveat here is you can't filter a linq-for-queries datasource to a notmapped field because it doesn't exist in it but in my case, a .toList() didn't cause any performance problems because the dataset was small, with only a few hundred records.
However, you can edit the incoming DatasourceRequest object to modify the filters and sorts to point at the sub model, after your controller read is hit.
I know there are a lot of questions around on this subject, but I've not managed to find one that actually explains how to solve my particular problem. Which I suppose means that it might be insoluble (I think it might be 'backwards' to EF's way of thinking), but I have to ask.
I have a model with three (abbreviated) POCOs as so:
[Table("People")]
public class Person {
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
}
public class Location {
public int LocationID { get; set; }
public int LocationTypeID { get; set; }
public virtual LocationType LocationType { get; set; }
}
public class Van : Location {
public int PartyID { get; set; }
public virtual Party Party { get; set; }
}
These are backed by (abbreviated) database tables (we write these by hand):
CREATE TABLE People (
PersonID INTEGER IDENTITY NOT NULL,
PersonName VARCHAR(255) NOT NULL,
PRIMARY KEY (PersonID)
)
CREATE TABLE Locations (
LocationID INTEGER IDENTITY NOT NULL,
LocationTypeID INTEGER NOT NULL,
FOREIGN KEY (LocationTypeID) REFERENCES LocationTypes(LocationTypeID)
)
CREATE TABLE Vans (
LocationID INTEGER NOT NULL,
PersonID INTEGER NOT NULL,
PRIMARY KEY (LocationID),
FOREIGN KEY (LocationID) REFERENCES Locations(LocationID),
FOREIGN KEY (PersonID) REFERENCES People(PersonID)
)
You can probably imagine what LocationTypes looks like.
Locations is the root of a table-per-type hierarchy - there are also check constraints in place to enforce this. Vans are a kind of location, as are other things irrelevant here like Warehouse.
Now, a Van belongs to a Person, in that we issue a van to an employee and it's their responsibility to fill it up with fuel, not crash it, take it to customer sites and order more stuff when they've used up all their supply of screws, drill bits and armoured DC cable. However, not every Person has a van (some of them work in pairs in one van), and the Person table doesn't have a foreign key which points to the Van - it's the other way around. This is in some sense a historical accident, but it models the situation quite neatly because while a Person doesn't have to have a Van, a Van most assuredly has to have a person.
So to my question: how do I get Person to have a navigation property with their Van in it?
public virtual Van Van { get; set; }
I've done a lot of playing around with data annotations and the fluent API, and the closest I've got is this in OnModelCreating:
modelBuilder.Entity<Van>()
.HasRequired(v => v.Person)
.WithOptional(p => p.Van);
Unfortunately this tries to populate the Van property with a proxy that yields a Location object. It might even be the right Location object (I haven't been able to check), but it's not realised that it should be looking for vans. I do suspect, however, that it might be trying to match PersonID against LocationID when it does the lookup - without the Fluent API mapping, I just get no vans at all, which is what I'd expect (all PersonID values are lower than the lowest LocationID values which correspond to vans so couldn't possibly find anything).
This would no doubt be quite easy if Person had a nullable foreign key to Van, but then we'd have foreign keys in both directions, and if we took the one out of Van then we'd not be modelling the absolutely essential constraint that a Van has a Person.
So, I suppose, Van owns this relationship, and the Van property on Person is an inverse navigation property, but it seems EF isn't very good at this kind of trick with one-to-ones even if one end is optional. Is there a way to make it work, or do I have to accept a compromise?
We generally refuse to compromise the database model for the sake of Entity Framework's missing features. What I really need is a way to tell EF that the Van property on Person can be populated by joining to Vans on Vans.PersonID = Person.PersonID.
The problem is that this is at the moment not supported. You mentioned that you didn't managed to find any question where would be your problem solved. I wonder if you find any question mentioning that EF doesn't support unique constraints / candidate key which is absolutely necessary to solve this type of one-to-one relations.
In database one-to-one relation can be achieved only if FK in dependent table is unique. This can be done by two ways: placing unique constraint (index) on FK column in dependent table or using PK in dependent table as FK to principal table.
EF enforces same rules for referential integrity as database but in case of one-to-one relationships and lack of support for unique constraint it doesn't support the former way. EF can model one-to-one relationship only by using PK of dependent table as FK to principal table.
You can vote for support of Unique constraints / candidate keys on Data UserVoice.
How to solve your particular issue? By cheating EF. Let EF think that you have one-to-many relation and place unique constraint on PersonID in Van table. Than update your Person like this:
[Table("People")]
public class Person {
public int PersonID { get; set; }
[Required]
public string PersonName { get; set; }
public virtual ICollection<Van> Vans { get; set; }
[NotMapped]
public Van Van
{
get { return Vans.FirstOrDefault(); }
set
{
Vans.Clear();
if (value != null)
{
Vans.Add(value);
}
}
}
}
It is pretty ugly workaround because Vans collection is still public. You can play with its visibility but make sure you understand few things:
Once Vans is not public you must map it in OnModelCreating and for that context must be able to see the property or you must provide mapping configuration which does that. Check this and this for some more information.
Vans property must not break rules for proxy creation to support lazy loading
Eager loading must use Vans property
I'm working on ASP.NET MVC 3 project using EF CodeFirst. I have a simple class with few attributes set on key column:
public class Tag
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[ScaffoldColumn(true)]
public short TagID { get; set; }
[Required]
[MaxLength(50)]
public string Name { get; set; }
}
As you can see there are DatabaseGenerated(DatabaseGeneratedOption.None) and ScaffoldColumn(true) attributes. That's because I want to be able to enter the TagID manually. Now when TagControler is added to the project I don't have the TagID column shown in neither of 5 generated views.
I know I can add it manually, but I wonder if this behavior is by design or I'm doing something wrong?
Primary keys aren't scaffolded as editable fields by default. Instead there is a hidden field for the key. If you wanted to change this behavior you could modify the templates but it is by design since generally it doesn't make sense to edit the primary key of an entity.
Here is some info on how to do this if you wanted to make this change any time you added a view or wanted to make some other custom change to the scaffolding:
http://blogs.msdn.com/b/joecar/archive/2011/01/06/add-the-asp-net-mvc-3-code-templates-to-your-application-with-nuget.aspx
I am trying to populate a JQGrid with LinQ but am having problems in getting a value from a foreign table.
Scenario: I have a Users table and a Country table. I am returning a List from the data layer and binding it to the grid. The values from the users table populate with no problem. My problem is when trying to link a JQGrid column to a column in the Country table, such as Country Name. If I debug the data returned from the data logic, the Country Name is filled in, but I can't find a way to link a JQGrid column to the Name column in the Country table. I tried, with no luck, the following:
<trirand:JQGridColumn DataField="Country.Name"/>
<trirand:JQGridColumn DataField="Country_Name"/>
Thanks for your time...
Have you tried using a ViewModel so it is not trying to bind to a navigation property?
something like:
public class UserViewModel
{
public int UserID { get; set; }
public string Username { get; set; }
public string CountryName { get; set; }
}
I'm working with a Razor MVC3 project
I have a model
public class ProductFormatModel
{
public int ID {get; set;}
public string SerialID { get; set; }
public ProductTypes ProductType { get; set; }
public List<ProductComponent> Components { get; set; }
}
The ProductComponent class has two properties: int ID and string Description.
I would like the controller to work with a strongly typed view of ProductFormatModel type to create a new ProductFormatModel. The Create view should look like this:
A textfield to insert SerialID (done)
A dropdownlist to select the value of the enumerator ProductType (done)
A listbox with different rows showing the "Description" property of ProductComponent. Every row should present a record in the database. The user must be able to select one or more rows and in this way the property "Components" should have those objects in the list.
The database is a simple DbContext. MyDB.Components gives me the recordset of table "Components"
How do I pass the values of the recordset from the controller to the view?
Should I call a listboxfor with multiselectlist?
Should I add another property to the model like List ComponentsToBeSelected in which I can pass the list?
One possible design:
Use two listboxes in your view. Load the first with all possible ProductComponents that are not in model.Components, and use ListBoxFor to bind the second to the model.Components list.
Place two buttons, Add and Remove, between the lists. Wire these up with jQuery to move items between the two listboxes.